2012-02-08 44 views
20

Trong ứng dụng của tôi, chúng tôi cần hiển thị khung Video nhận được từ máy chủ đến ứng dụng Android của chúng tôi,
Máy chủ đang gửi dữ liệu video @ 50 khung hình/giây, đã mã hóa trong WebM, sử dụng libvpx để mã hóa và giải mã những hình ảnh,Hiển thị ảnh YUV trong Android

Bây giờ sau khi giải mã từ libvpx dữ liệu YUV nhận được nó, chúng tôi có thể hiển thị trên cách bố trí hình ảnh,

việc thực hiện hiện nay là một cái gì đó như thế này,

Trong JNI/Native C++, chúng tôi đang chuyển đổi dữ liệu YUV thành Dữ liệu RGB Trong khuôn khổ Android, gọi

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

Để tạo hình ảnh bitmap,

để hiển thị hình ảnh trên IMAGExem sử dụng đoạn mã sau,

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

truy vấn của tôi là, tổng thể chức năng này đang xấp xỉ 40 ms, có cách nào để tối ưu hóa nó,
1 - Có cách nào để hiển thị dữ liệu YUV cho imageView không?

2 - Có cách nào khác để tạo ra hình ảnh (hình ảnh Bitmap) từ dữ liệu RGB,

3 - Tôi tin rằng tôi luôn luôn tạo ra hình ảnh, nhưng tôi nghĩ tôi nên tạo bitmap chỉ một lần và làm/cung cấp bộ đệm mới luôn, như và khi chúng tôi nhận được.
vui lòng chia sẻ quan điểm của bạn.

+0

'bitmap.copyPixelsFromBuffer (ByteBuffer.wrap (bits));' chuyển đổi từ YUV sang RGB? Hay bạn đang nói đó là những gì bạn đang làm trong bản địa? – weston

+0

Đây là một cách để làm điều đó. Hãy xem http://stackoverflow.com/questions/9192982/displaying-yuv-image-in-android – bob

Trả lời

30

Mã sau giải quyết vấn đề của bạn và có thể mất ít thời gian hơn trên dữ liệu Định dạng Yuv vì lớp YuvImage được cung cấp với Android-SDK.

Bạn có thể thử này,

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

hoặc

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

Tôi đã thử phương thức decodeYUV420SP() của bạn nhưng hình ảnh mà nó tạo ra không tốt. Nó có đầy sóng màu vàng và màu xanh lá cây. Tôi đã làm điều này và nó hoạt động: http: // stackoverflow.com/questions/5272388/need-help-with-androids-nv21-format/12702836 # 12702836 – Derzu

+1

Tôi không hiểu tại sao rgba [yp] = ... bị dịch chuyển bởi 8 bit. Dòng nhận xét là chính xác hơn. Tôi nhận được một hình ảnh xoay. –

+5

có cách nào để thực hiện việc này với nén không mất dữ liệu (tức là không phải là JPEG) không? –

-2

Tạo một bitmap sau khi nhận rộng và chiều cao trong onCreate.

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

Và trong 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; 
} 

Và thưởng.

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

finalBitmap = Bitmap.createBitmap(editedBitmap, 0, 0, widthPreview, heightPreview, matrix, true); 
Các vấn đề liên quan