2015-02-08 2 views
0

Я использую текущую поточную библиотеку под названием Cine.io, чтобы сохранить кадр из потока на внешнее хранилище Android.Как преобразовать изображение при использовании Open GL Framebuffer в Android

В самой библиотеке используется ресурс Google Grafika.

Когда я просто настроил ByteBufferand и прочитал его с помощью GLReadPixel, изображение будет сохранено правильно, но оно будет инвертировано, так как изображения GL имеют обратные координаты координат BMP.

Для решения этой проблемы я считаю, что наиболее эффективным решением является использование открытого фреймбуфера GL для рендеринга входящего кадра, переворачивание его с помощью орто-матрицы, а затем чтение его с помощью GLReadPixel, чтобы сохранить его на диске ,

Это код, который я считаю, будет достичь этой цели:

int width = getWidth(); 
    int height = getHeight(); 
    ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4); 
    buf.order(ByteOrder.LITTLE_ENDIAN); 


    int[] fboId = new int[1]; 
    int[] rendId = new int[1]; 
    float[] projMatrix = new float[16]; 

    GLES20.glGenFramebuffers(1, fboId, 0); 
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId[0]); 

     GLES20.glGenRenderbuffers(1, rendId, 0); 
    GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, rendId[0]); 
    GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER,GLES20.GL_RGBA4, width, height); 


    switch(GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER)){ 
     case GLES20.GL_FRAMEBUFFER_COMPLETE: 
      Log.i(TAG, "Is Complete"); 
      break; 
     case GLES20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: 
      Log.i(TAG, "Incomplete Attachment"); 
      break; 
     case GLES20.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: 
      Log.i(TAG, "Missing Attachment"); 
      break; 
     default: Log.i(TAG, "Something else is going on"); 

    } 
    GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_RENDERBUFFER,rendId[0]); 
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboId[0]); 
    GLES20.glViewport(0,0,width, height); 
    android.opengl.Matrix.orthoM(projMatrix, 0, 0, width, height, 0, -1, 1); 


    GLES20.glReadPixels(0, 0, width, height, 
      GLES20.GL_RGBA4, GLES20.GL_UNSIGNED_BYTE, buf); 

    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); 




    GlUtil.checkGlError("glReadPixels"); 
    buf.rewind(); 

Однако код просто создает пустой файл изображения, который является пустым (размер 3.6kb). Кроме того, переменный блок «buff» состоит только из 0 после вызова метода GLreadpixels.

Наконец, если я установил BindFramebuffer равным 0 (привязка по умолчанию) и поместил его перед вызовом GLReadPixels, изображение будет отображаться, но все же инвертировано - это похоже на то, что команды Framebuffer никогда не взаимодействовали с ним.

Как я могу это решить?

PS: многие люди пытаются ответить на предыдущую, более запутанную версию вопроса ниже - но суть этого по-прежнему сохраняется.

ответ

0

Вы всегда можете перевернуть буфер вручную. Я не работал с java ByteBuffer, поэтому следующий код может не работать, но в основном это должен быть пример.

//num channels being the amount of channels per pixel, 4 representing r, g, b, a 
int num_channels = 4; 
//allocate buffer size 
ByteBuffer new_buf = ByteBuffer.allocateDirect(width * height * num_channels); 
buf.order(ByteOrder.LITTLE_ENDIAN); 

//calculate row size of image 
int row_size = width * num_channels 
//loop through the contents of the buffer and flip it 
for (int y = 0; y < height; ++y) { 
    for (int x = 0; x < row_size; ++x) { 
     //put a row of bytes starting from the end of the buffer into the start of the new buffer 
     new_buf.put(buf.get(((height - (y + 1)) - x) * row_size)); 
    } 
} 

Однако это довольно медленно и определенно не идеально подходит для цикла обновления. Вместо этого в коде рендеринга вы можете изменить способ проецирования текстуры на экран с использованием матрицы. Попробуйте использовать glOrtho так:

glMatrixMode(GL_PROJECTION); 
glLoadIdentity(); 
glOrtho(0.0f, window_width, window_height, 0.0f, -1.0f, 1.0f); 

Это должно перевернуть ваши текстуры при визуализации. Попытайтесь экспериментировать и возиться с разными значениями, чтобы почувствовать это.

+0

Определенно прошел через песню и танец фреймбуфера, чтобы я мог достичь варианта № 2. Моя проблема при определении методов сопоставления в Android. Я буду. – Laurent

+0

Я думаю, что код, который вы предоставили для опции № 2, для GL v1.0. Поскольку я использую GL 2.0 в Android, у меня возникли проблемы с поиском соответствующего кода для привязки преобразования к фреймбуферу. – Laurent

+0

О, право. К сожалению, я все еще довольно новичок в openGL, но думаю, что я все еще могу помочь. Итак, я немного смущен, вы читаете пиксели из буфера кадров по умолчанию (0) и сохраняете их на диск? Зачем вам нужен буфер кадров, который вы создали над ним? Разве вы не должны быть привязаны к идентификатору буфера фрейма, который вы создали выше? Что бы я сделал, это привязка к буферу фрейма, который вы создали выше, при рендеринге, чтобы он отображался в буфер кадра (он не будет отображаться на экране). Когда вы применяете матричное преобразование, вы можете считывать пиксели из этого фреймового буфера. – QualityPixels

Смежные вопросы