Android org.webrtc.VideoRenderer.I420Массивы кадров из изображения

1

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

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

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

Теги:
webrtc
android-image
yuv

2 ответа

2
Лучший ответ

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, и я создаю кадр I420. Теперь я получаю эту ошибку Java.Lang.ArrayIndexOutOfBoundsException: length = 1179648; regionStart = 0; regionLength = 2073600 для mFrame.yuvPlanes [0]. Как я могу убедиться, что независимо от размера изображения, я должен иметь возможность его потоковой передачи?
  • 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
        }

Ещё вопросы

Сообщество Overcoder
Наверх
Меню