2012-02-08 18 views
20

En mi aplicación, tenemos que mostrar el marco de video recibe desde el servidor a nuestra aplicación Android,
El servidor está enviando datos de video a 50 fotogramas por segundo, codificado en WebM es decir usando libvpx para codificar y decodificar las imágenes,Visualización de la imagen YUV en Android

Ahora después de la decodificación de libvpx sus datos YUV conseguir, que podamos mostrado sobre el diseño de la imagen,

la implementación actual es algo como esto,

En/código JNI nativo C++, estamos convirtiendo los datos de YUV en datos RGB En el marco de Android, llamando

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

Para crear la imagen de mapa de bits,

para mostrar la imagen sobre imageView usando siguiente código,

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

Mi consulta es, en general esta función está tomando aprox 40 ms, ¿hay alguna forma de optimizarlo?
1 - ¿Hay alguna forma de mostrar los datos YUV a imageView?

2 - ¿Hay alguna otra manera de crear la imagen (imagen de mapa de bits) a partir de los datos RGB,

3 - Creo que siempre estoy creando la imagen, pero supongo que debería crear mapa de bits sólo una vez y hacer/Suministrar siempre nuevo buffer, como y cuando lo recibamos.
por favor comparta sus puntos de vista.

+0

'bitmap.copyPixelsFromBuffer (ByteBuffer.wrap (bits));' qué la conversión de YUV a RGB? ¿O estás diciendo que eso es lo que estás haciendo en tu lengua materna? – weston

+0

Aquí hay una manera de hacerlo. Consulte http://stackoverflow.com/questions/9192982/displaying-yuv-image-in-android – bob

Respuesta

30

El siguiente código resuelve su problema y puede tomar menos tiempo en datos de formato Yuv porque la clase YuvImage se proporciona con Android-SDK.

Puede probar esto,

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

o

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

Probé su método decodeYUV420SP() pero la imagen que crea no es buena. Está lleno de olas amarillas y verdes. Hice este y sus trabajos: http: // stackoverflow.com/questions/5272388/need-help-with-androids-nv21-format/12702836 # 12702836 – Derzu

+1

No entiendo por qué el rgba [yp] = ... se desplaza 8 bits. La línea comentada es más correcta. Obtengo una imagen rotada. –

+5

¿hay alguna manera de hacerlo con compresión sin pérdida (es decir, no JPEG)? –

-2

Crear un mapa de bits después de conseguir anchura y altura en onCreate.

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

Y en onPreviewFrame.

int[] rgbData = decodeGreyscale(aNv21Byte,widthPreview,heightPreview); 
editedBitmap.setPixels(rgbData, 0, widthPreview, 0, 0, widthPreview, heightPreview); 

Y

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

y Bonus.

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

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