2012-02-08 3 views
20

В моем приложении нам нужно отобразить получение видеофрагмента с сервера на наше приложение для Android,
Сервер отправляет видеоданные с частотой 50 кадров в секунду, закодированные в WebM, то есть используя libvpx для кодирования и декодировать изображения,Отображение изображения YUV в Android

Теперь после декодирования с libvpx его получения данных YUV, что мы можем отображаться поверх макета изображения,

текущая реализация является чем-то вроде этого,

В JNI код/​​Native 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 - Есть ли другой способ создания изображения (Bitmap изображение) из данных RGB,

3 - Я считаю, что я всегда создаю образ, но я полагаю, я должен создать изображение только один раз и сделать/всегда поставляйте новый буфер, когда и когда мы получаем.
поделитесь своими мнениями.

+0

'bitmap.copyPixelsFromBuffer (ByteBuffer.wrap (биты));' делает преобразование из YUV в RGB? Или вы говорите, что это то, что вы делаете в родном? – weston

+0

Вот один из способов сделать это. Проверьте http://stackoverflow.com/questions/9192982/displaying-yuv-image-in-android – bob

ответ

30

Следующий код решает вашу проблему, и может потребоваться меньше времени на данные формата 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(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

+1

Я не понимаю, почему rgba [yp] = ... сдвигается на 8 бит. Вышеупомянутая строка правильнее. Я получаю повернутое изображение. –

+5

есть ли способ сделать это с сжатием без потерь (т. Е. Без JPEG)? –

-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); 
Смежные вопросы