2017-01-25 4 views
0

Я продолжаю надеяться, что какой-то код появится в Интернете, но ничего не получается;) Я использую этот пример github. WebRTC входящий объект I420Frame, кажется, имеет 3 массива yuvPlanesAndroid org.webrtc.VideoRenderer.I420Frame массивы с изображения

Обычное приложение для камеры Android получает PreviewCallback.onPreviewFrame byte [] как единый массив байтов. Моя задача - передать изображение как I420 с регулярным интервалом времени. Может кто-нибудь помочь мне в том, как сгенерировать I420Frames yuvPlanes из одного байтового [] массива, такого как JPEG/PNG-файл?

Это очень важно. Все ответы оценены.

ответ

1

PreviewCallback.onPreviewFrame() никогда не будет возвращать поток JPEG или PNG. Вы должны проверить свою камеру getSupportedPreviewFormats()(обратите внимание, что это может отличаться для передних и задних камер). В этом списке у вас есть NV21. Если вам повезет, вы можете выбрать YV12 с уровня API 12 (обратите внимание, что некоторые устройства, например Amazon Fire HD (2012), об этом говорят и фактически не могут доставить YV12).

Легко построить I420Frame из массива в YV12 байт:

private VideoRenderer.I420Frame mFrame; 
void onPreviewFrame(byte[] yv12_data, Camera camera) { 
    if (mFrame == null) { 
     Camera.Parameters params = camera.getParameters(); // this is an expensive call, don't repeat it on every frame! 
     assert(params.getPreviewFormat() == ImageFormat.YV12); 
     int width = params.getPreviewSize().width; 
     int stride_y = 16 + ((width-1)/16)*16; 
     int stride_uv = 16 + ((stride_y/2-1)/16)*16; 
     int height = params.getPreviewSize().height; 
     mFrame = new VideoRenderer.I420Frame(width, height, 0, new int[]{stride_y, stride_uv, stride_uv}, new ByteBuffer[3], 0); 
    } 

    mFrame.yuvPlanes[0] = ByteBuffer.wrap(yv12_data, 0, mFrame.yuvStrides[0]*mFrame.height) // Y 
    mFrame.yuvPlanes[1] = ByteBuffer.wrap(yv12_data, mFrame.yuvStrides[0]*mFrame.height+mFrame.yuvStrides[2]*mFrame.height/2, mFrame.yuvStrides[1]*mFrame.height/2) // U 
    mFrame.yuvPlanes[2] = ByteBuffer.wrap(yv12_data, mFrame.yuvStrides[0]*mFrame.height, mFrame.yuvStrides[2]*mFrame.height/4) // V 

    ... do something with the frame 
} 

Для NV21, необходимо выделить плоскости U и V:

private VideoRenderer.I420Frame mFrame; 
void onPreviewFrame(byte[] nv21_data, Camera camera) { 
    if (mFrame == null) { 
     Camera.Parameters params = camera.getParameters(); // this is an expensive call, don't repeat it on every frame! 
     assert(params.getPreviewFormat() == ImageFormat.NV21); 
     int width = params.getPreviewSize().width; 
     int height = params.getPreviewSize().height; 
     mFrame = new VideoRenderer.I420Frame(width, height, 0, new int[]{width, width/2, width/2}, new ByteBuffer[3], 0); 
     mFrame.yuvPlanes[1] = ByteBuffer.wrap(new byte[width*height/4]); 
     mFrame.yuvPlanes[2] = ByteBuffer.wrap(new byte[width*height/4]); 
    } 

    mFrame.yuvPlanes[0] = ByteBuffer.wrap(nv21_data, 0, mFrame.width*mFrame.height) // Y 
    for (int top=0, from=mFrame.width*mFrame.height; from < mFrame.width*mFrame.height*3/2; to++, from+=2) { 
     mframe.yuvPlanes[1][to] = nv21_data[from+1]; // U 
     mframe.yuvPlanes[2][to] = nv21_data[from]; // V 
    } 

    ... do something with the frame 
} 
+0

Спасибо за ответ сэр. Я получил массив байтов из изображения YUV, и я создаю I420Frame. Теперь я получаю эту ошибку Java.Lang.ArrayIndexOutOfBoundsException: length = 1179648; regionStart = 0; regionLength = 2073600 для mFrame.yuvPlanes [0]. Как я могу удостовериться, что независимо от размера изображения я должен был бы передать его? – user2801184

+0

Просьба представить более подробную информацию, например. стека этого исключения. Какой формат предварительного просмотра вы используете? Размер предварительного просмотра? –

0
I420Frame onPreviewFrame(byte[] yv12_data) 
     { 
      if (mFrame == null) 
      { 
       //Camera.Parameters params = camera.getParameters(); // this is an expensive call, don't repeat it on every frame! 
       //assert(params.getPreviewFormat() == ImageFormat.YV12); 
       int width = 640; 
       int stride_y = 16 + ((width - 1)/16) * 16; 
       int stride_uv = 16 + ((stride_y/2 - 1)/16) * 16; 
       int height = 480; 
       mFrame = new VideoRenderer.I420Frame(width, height, new int[] { stride_y, stride_uv, stride_uv }, new ByteBuffer[3]); 
      }     

      mFrame.YuvPlanes[0] = ByteBuffer.Wrap(yv12_data, 0, mFrame.YuvStrides[0] * mFrame.Height); // Y 
      mFrame.YuvPlanes[1] = ByteBuffer.Wrap(yv12_data, (mFrame.YuvStrides[0] * mFrame.Height) , mFrame.YuvStrides[1] * mFrame.Height);// U 
      mFrame.YuvPlanes[2] = ByteBuffer.Wrap(yv12_data, (mFrame.YuvStrides[0] * mFrame.Height)+ (mFrame.YuvStrides[1] * mFrame.Height), mFrame.YuvStrides[2] * mFrame.Height); // V 
      return mFrame; 
      // ... do something with the frame 
     } 
Смежные вопросы