2009-07-03 69 views
1

我已經分配了編寫程序的任務,該程序需要一個原始YUV示例文件並將其顯示在Cocoa OpenGL程序中。如何在Cocoa OpenGL程序中顯示原始YUV幀

我是一名實習生,我很少或沒有線索如何開始。我一直在閱讀關於YUV的維基百科&文章,但我找不到有關如何打開原始YUV文件,提取數據並將其轉換爲RGB並將其顯示在視圖窗口中的任何良好源代碼。

從本質上講,我需要與任務 - 如何 從樣本YUV文件 提取YUV數據 - 如何給YUV數據轉換爲RGB色彩空間 - 如何顯示RGB色彩空間的以下幾個方面幫助在OpenGL中。 (這個我認爲我可以用時間計算出來,但是我真的需要前兩點的幫助)

請告訴我要使用的課程,或者指向我可以學習YUV圖形/視頻的地方顯示器

回答

1

這個答案是不正確的,請參閱其他答案和評論。留給後人的原始答案爲後人。


不能直接顯示。 您需要將其轉換爲RGB紋理。正如您可能從Wikipedia收集到的那樣,YUV色彩空間有一些變化。確保你使用的是正確的。

對於每個像素,從YUV到RGB的轉換是直接的線性轉換。你只需要對每個像素單獨做同樣的事情。

將圖像轉換爲RGB後,可以通過創建紋理進行顯示。您需要調用glGenTextures()來分配紋理句柄,glBindTexture()將紋理綁定到渲染上下文,並且glTexImage2D()將紋理數據上傳到GPU。爲了渲染它,你再次調用glBindTexture(),然後渲染一個正確設置了紋理座標的四邊形。

// parameters: image: pointer to raw YUV input data 
//    width: image width (must be a power of 2) 
//    height: image height (must be a power of 2) 
// returns: a handle to the resulting RGB texture 
GLuint makeTextureFromYUV(const float *image, int width, int height) 
{ 
    float *rgbImage = (float *)malloc(width * height * 3 * sizeof(float)); // check for NULL 
    float *rgbImagePtr = rgbImage; 

    // convert from YUV to RGB (floats used here for simplicity; it's a little 
    // trickier with 8-bit ints) 
    int y, x; 
    for(y = 0; y < height; y++) 
    { 
     for(x = 0; x < width; x++) 
     { 
      float Y = *image++; 
      float U = *image++; 
      float V = *image++; 
      *rgbImagePtr++ = Y    + 1.13983f * V; // R 
      *rgbImagePtr++ = Y - 0.39465f * U - 0.58060f * V; // G 
      *rgbImagePtr++ = Y + 2.03211f * U;     // B 
     } 
    } 

    // create texture 
    GLuint texture; 
    glGenTextures(1, &texture); 

    // bind texture to render context 
    glBindTexture(GL_TEXTURE_2D, texture); 

    // upload texture data 
    glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_FLOAT, rgbImage); 

    // don't use mipmapping (since we're not creating any mipmaps); the default 
    // minification filter uses mipmapping. Use linear filtering for minification 
    // and magnification. 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

    // free data (it's now been copied onto the GPU) and return texture handle 
    free(rgbImage); 
    return texture; 
} 

要渲染:

glBindTexture(GL_TEXTURE_2D, texture); 

glBegin(GL_QUADS); 
    glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 0.0f, 0.0f); 
    glTexCoord2f(1.0f, 0.0f); glVertex3f(64.0f, 0.0f, 0.0f); 
    glTexCoord2f(1.0f, 1.0f); glVertex3f(64.0f, 64.0f, 0.0f); 
    glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, 64.0f, 0.0f); 
glEnd(); 

而且不要忘了初始化過程中在某些點打電話glEnable(GL_TEXTURE_2D),以及關閉期間調用glDeleteTextures(1, &texture)

+0

感謝很多的信息亞當我真的很感激。現在你能告訴我如何從硬盤中提取原始數據文件嗎?我熟悉NSOpenPanel,我可以使用它來提取數據文件路徑,但是,如何使用文件路徑並將YUV文件加載到應用程序中? – ReachConnection 2009-07-03 20:28:56

+0

假設文件只包含像素,只需使用NSData或NSFileHandle並讀取所有內容。如果文件包含元數據(如大小信息),則必須使用標準C指針和/或結構運算符來解釋該元數據。 – 2009-07-04 01:20:50

6

Adam Rosenfield的評論不正確。在Mac上,您可以使用GL_YCBCR_422_APPLE紋理格式顯示YCbCr(等同於YUV的數字紋理)紋理,如APPLE_ycbcr_422擴展名中所述。

8

我已經完成了從CCD相機捕獲的YUV幀。不幸的是,有許多不同的YUV格式。我相信蘋果用於GL_YCBCR_422_APPLE紋理格式的技術是2VUY422。將圖像從由IIDC火線相機產生的YUV422幀轉換爲2VUY422,我使用以下:

void yuv422_2vuy422(const unsigned char *theYUVFrame, unsigned char *the422Frame, const unsigned int width, const unsigned int height) 
{ 
    int i =0, j=0; 
    unsigned int numPixels = width * height; 
    unsigned int totalNumberOfPasses = numPixels * 2; 
    register unsigned int y0, y1, y2, y3, u0, u2, v0, v2; 

    while (i < (totalNumberOfPasses)) 
    { 
     u0 = theYUVFrame[i++]-128; 
     y0 = theYUVFrame[i++]; 
     v0 = theYUVFrame[i++]-128; 
     y1 = theYUVFrame[i++]; 
     u2 = theYUVFrame[i++]-128; 
     y2 = theYUVFrame[i++]; 
     v2 = theYUVFrame[i++]-128; 
     y3 = theYUVFrame[i++]; 

     // U0 Y0 V0 Y1 U2 Y2 V2 Y3 

     // Remap the values to 2VUY (YUYS?) (Y422) colorspace for OpenGL 
     // Y0 U Y1 V Y2 U Y3 V 

     // IIDC cameras are full-range y=[0..255], u,v=[-127..+127], where display is "video range" (y=[16..240], u,v=[16..236]) 

     the422Frame[j++] = ((y0 * 240)/255 + 16); 
     the422Frame[j++] = ((u0 * 236)/255 + 128); 
     the422Frame[j++] = ((y1 * 240)/255 + 16); 
     the422Frame[j++] = ((v0 * 236)/255 + 128); 
     the422Frame[j++] = ((y2 * 240)/255 + 16); 
     the422Frame[j++] = ((u2 * 236)/255 + 128); 
     the422Frame[j++] = ((y3 * 240)/255 + 16); 
     the422Frame[j++] = ((v2 * 236)/255 + 128); 
    } 
} 

對於YUV視頻源的有效顯示,則可能希望使用Apple's client storage extension,它可以設置使用類似以下內容:

glEnable(GL_TEXTURE_RECTANGLE_EXT); 
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 1); 

glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, videoImageWidth * videoImageHeight * 2, videoTexture); 
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_SHARED_APPLE); 
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); 

glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 

glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, videoImageWidth, videoImageHeight, 0, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_REV_APPLE, videoTexture);  

這可以讓你迅速改變了存儲在您的客戶端視頻紋理中的數據每個幀之前在屏幕上顯示。

要繪製,那麼你可以使用如下代碼:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   
glEnable(GL_TEXTURE_2D); 

glViewport(0, 0, [self frame].size.width, [self frame].size.height); 

glMatrixMode(GL_PROJECTION); 
glLoadIdentity(); 
NSRect bounds = NSRectFromCGRect([self bounds]); 
glOrtho((GLfloat)NSMinX(bounds), (GLfloat)NSMaxX(bounds), (GLfloat)NSMinY(bounds), (GLfloat)NSMaxY(bounds), -1.0, 1.0); 

glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 1); 
glTexSubImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, videoImageWidth, videoImageHeight, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_REV_APPLE, videoTexture); 

glMatrixMode(GL_TEXTURE); 
glLoadIdentity(); 

glBegin(GL_QUADS); 
    glTexCoord2f(0.0f, 0.0f); 
    glVertex2f(0.0f, videoImageHeight); 

    glTexCoord2f(0.0f, videoImageHeight); 
    glVertex2f(0.0f, 0.0f); 

    glTexCoord2f(videoImageWidth, videoImageHeight); 
    glVertex2f(videoImageWidth, 0.0f); 

    glTexCoord2f(videoImageWidth, 0.0f); 
    glVertex2f(videoImageWidth, videoImageHeight);  
glEnd();