with - rendering opengl




ffmpeg視頻到opengl紋理 (2)

調用glTexSubImage2D時是否初始化了紋理? 您需要調用glTexImage2D (而不是Sub )一次來初始化紋理對象。 對數據指針使用NULL,然後OpenGL將初始化紋理而不復制數據。 回答

編輯

你沒有提供mipmaping級別。 所以你禁用了mipmaping嗎?

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILER, linear_interpolation ? GL_LINEAR : GL_NEAREST);

編輯2顛倒的圖像並不令人驚訝,因為大多數圖像格式的原點位於左上角,而OpenGL將紋理圖像的原點放在左下角。 你看到那條帶似乎是錯誤的行間距。

編輯3

一年前我自己做過這種事。 我給fqmpeg寫了一個小包裝器,我稱之為aveasy https://github.com/datenwolf/aveasy

這是一些代碼,用於將使用aveasy獲取的數據放入OpenGL紋理中:

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include <GL/glew.h>

#include "camera.h"
#include "aveasy.h"

#define CAM_DESIRED_WIDTH 640
#define CAM_DESIRED_HEIGHT 480

AVEasyInputContext *camera_av;
char const *camera_path = "/dev/video0";
GLuint camera_texture;

int open_camera(void)
{
    glGenTextures(1, &camera_texture);

    AVEasyInputContext *ctx;

    ctx = aveasy_input_open_v4l2(
        camera_path,
        CAM_DESIRED_WIDTH,
        CAM_DESIRED_HEIGHT,
        CODEC_ID_MJPEG,
        PIX_FMT_BGR24 );
    camera_av = ctx;

    if(!ctx) {
        return 0;
    }

    /* OpenGL-2 or later is assumed; OpenGL-2 supports NPOT textures. */
    glBindTexture(GL_TEXTURE_2D, camera_texture[i]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(
        GL_TEXTURE_2D,  
        0,
        GL_RGB, 
        aveasy_input_width(ctx),
        aveasy_input_height(ctx),
        0,
        GL_BGR,
        GL_UNSIGNED_BYTE,
        NULL );

    return 1;
}

void update_camera(void)
{
    glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE );
    glPixelStorei( GL_UNPACK_LSB_FIRST,  GL_TRUE  );
    glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
    glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0);
    glPixelStorei( GL_UNPACK_SKIP_ROWS, 0);
    glPixelStorei( GL_UNPACK_ALIGNMENT, 1);

    AVEasyInputContext *ctx = camera_av;
    void *buffer;

    if(!ctx)
        return;

    if( !( buffer = aveasy_input_read_frame(ctx) ) )
        return;

    glBindTexture(GL_TEXTURE_2D, camera_texture);
    glTexSubImage2D(
        GL_TEXTURE_2D,
        0,
        0,
        0,
        aveasy_input_width(ctx),
        aveasy_input_height(ctx),
        GL_BGR,
        GL_UNSIGNED_BYTE,
        buffer );
}


void close_cameras(void)
{
    aveasy_input_close(camera_av);
    camera_av=0;
}

我在一個項目中使用它,它在那里工作,所以這個代碼是經過測試的。

我正在嘗試使用ffmpeg渲染幀並將其從視頻轉換為OpenGL紋理以放置在四邊形上。 我已經筋疲力盡了谷歌並沒有找到答案,我找到了答案,但似乎沒有一個有效。

基本上,我使用avcodec_decode_video2()來解碼幀,然後使用sws_scale()將幀轉換為RGB,然後使用glTexSubImage2D()從中創建一個openGL紋理,但似乎無法正常工作。

我確保“目的地”AVFrame在SWS上下文設置中具有2維的功能。 這是我的代碼:

SwsContext *img_convert_ctx = sws_getContext(pCodecCtx->width,
                pCodecCtx->height, pCodecCtx->pix_fmt, 512,
                256, PIX_FMT_RGB24, SWS_BICUBIC, NULL,
                NULL, NULL);

//While still frames to read
while(av_read_frame(pFormatCtx, &packet)>=0) {
    glClear(GL_COLOR_BUFFER_BIT);

    //If the packet is from the video stream
    if(packet.stream_index == videoStream) {
        //Decode the video
        avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

        //If we got a frame then convert it and put it into RGB buffer
        if(frameFinished) {
            printf("frame finished: %i\n", number);
            sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);

            glBindTexture(GL_TEXTURE_2D, texture);
            //gluBuild2DMipmaps(GL_TEXTURE_2D, 3, pCodecCtx->width, pCodecCtx->height, GL_RGB, GL_UNSIGNED_INT, pFrameRGB->data);
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, 512, 256, GL_RGB, GL_UNSIGNED_BYTE, pFrameRGB->data[0]);
            SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, number);
            number++;
        }
    }

    glColor3f(1,1,1);
    glBindTexture(GL_TEXTURE_2D, texture);
    glBegin(GL_QUADS);
        glTexCoord2f(0,1);
        glVertex3f(0,0,0);

        glTexCoord2f(1,1);
        glVertex3f(pCodecCtx->width,0,0);

        glTexCoord2f(1,0);
        glVertex3f(pCodecCtx->width, pCodecCtx->height,0);

        glTexCoord2f(0,0);
        glVertex3f(0,pCodecCtx->height,0);

    glEnd();

正如您在該代碼中看到的那樣,我還將幀保存到.ppm文件只是為了確保它們實際呈現,它們就是這樣。

正在使用的文件是845x480的.wmv,這可能是問題嗎? 事實上,我只是告訴它去512x256?

PS我看過這個Stack Overflow問題,但它沒有幫助。

另外,我也有glEnable(GL_TEXTURE_2D)並且只是通過加載正常的bmp來測試它。

編輯

我現在正在屏幕上看到一個圖像,但這是一個亂碼,我猜測將事情改變為2的冪(在我的代碼中顯示的解碼, swscontextgluBuild2DMipmaps中)。 我通常與上面顯示的代碼幾乎完全相同,只是我已經將glTexSubImage2D更改為gluBuild2DMipmaps並將類型更改為GL_RGBA

這是框架的樣子:

再次編輯

剛剛意識到我沒有展示如何設置pFrameRGB的代碼:

//Allocate video frame for 24bit RGB that we convert to.
AVFrame *pFrameRGB;
pFrameRGB = avcodec_alloc_frame();

if(pFrameRGB == NULL) {
    return -1;
}

//Allocate memory for the raw data we get when converting.
uint8_t *buffer;
int numBytes;
numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
buffer = (uint8_t *) av_malloc(numBytes*sizeof(uint8_t));

//Associate frame with our buffer
avpicture_fill((AVPicture *) pFrameRGB, buffer, PIX_FMT_RGB24,
    pCodecCtx->width, pCodecCtx->height);

現在我已經將PIX_FMT_RGB24PixelFormat avgpicture_get_sizePIX_FMT_RGB24 ,我也在SwsContext完成了這項工作, SwsContext更改為GL_RGB並獲得了稍好的圖像,但看起來我仍然缺少線條並且它仍然有點拉伸:

另一個編輯

在遵循Macke的建議並將實際分辨率傳遞給OpenGL之後,我得到的框架幾乎是合適的,但仍然有點偏斜,黑白分明,現在只有6fps而不是110fps:

PS

我有一個函數在sws_scale()之後將幀保存到圖像中,並且它們的顏色很好,所以OGL中的所有內容都使它成為B&W。

最後編輯

加工! 好吧,我現在有它工作,基本上我沒有將紋理填充到2的冪,只是使用視頻的分辨率。

我正確地顯示了紋理,並在正確的glPixelStorei()中進行了幸運的猜測

glPixelStorei(GL_UNPACK_ALIGNMENT, 2);

另外,如果其他人有subimage()顯示像我這樣的空白問題,你必須用glTexImage2D()填充紋理至少一次,所以我在循環中使用它一次,然後使用glTexSubImage2D()

感謝Macke和datenwolf的所有幫助。


正在使用的文件是845x480的.wmv,這可能是問題嗎? 事實上,我只是告訴它去512x256?

是!

條紋圖案顯然表明您的數據大小不匹配(行大小)。 (由於顏色正確,RGB與BGR對比BGRA和n分量是正確的。)

你告訴OpenGL你上傳的紋理是512x256(它不是,AFAICT)。 使用真實尺寸(NPOT,如果它不古老,你的卡應該支持它)。

否則,請將數據上傳為1024x512紋理之前調整大小/填充數據。

更新

我對OpenGL更熟悉你正在調用的其他功能。

sxs_scale可能是您想要的(即將圖像縮小到底池大小)。 但是,縮放每個幀可能會很慢。

我會使用填充(這意味著,將一個小圖像(您的視頻)複製到一個大紋理的一部分(opengl)

其他一些提示:

  • 你真的需要mipmap嗎? 只有在需要平滑地縮小紋理時才生成它們(通常僅在某些3d幾何體上需要時才需要)。
  • 如果要渲染視頻,請避免在運行時生成mipmap(特別是,不要使用gluBuildMipMaps2D,因為它可能在軟件中運行。 如果需要mipmapping(例如使用GL_GENERATE_MIPMAP紋理參數),還有其他更快的方法。 這個帖子有更多信息。
  • 避免重複調用glTexImage,因為這會創建一個新紋理。 glTexSubImage只是更新紋理的一部分,這可能對你更好。
  • 如果你想在一個步驟中上傳紋理(出於性能原因這是優選的),但數據不太合適,請查看glPixelStore以設置像素和行步長。 我懷疑從sxs_scale / wmw給出的數據在每行的末尾(黑線)有一些填充。 可能使每行開始於偶數8-16-32字節的邊界。




render-to-texture