2009-07-03 10 views
1

サンプルの生のYUVファイルを取り込み、それをCocoa OpenGLプログラムで表示するプログラムを作成するタスクが割り当てられました。Cocoa OpenGLプログラムで生のYUVフレームを表示する方法

私は自分の仕事でインターンをしており、始める方法がほとんどまたは全く分かりません。私はYUVのwikipedia &の記事を読んできましたが、生のYUVファイルを開いてデータを抽出し、RGBに変換してビューウィンドウに表示する方法について、良いソースコードが見つかりませんでした。

基本的に、私はRGBの色空間を表示するには - どのようにRGB色空間 にYUVデータを変換するために、サンプルYUVファイルから - どのようにYUVデータを抽出するために - どのようにタスク の次の側面に助けが必要OpenGLで(これは私が時間を考え出すことができると思うが、最初の2点については本当に助けが必要だ)

使用するクラスを教えてもらったり、YUVのグラフィック/ビデオ表示

答えて

1

この回答は正しくありません。他の回答とコメントを参照してください。後世のために残した原文の答え。


あなたはそれを直接表示することができません。 RGBテクスチャに変換する必要があります。あなたがWikipediaから集まったかもしれないので、YUV色空間にはたくさんのバリエーションがあります。あなたが正しいものを使用していることを確認してください。

各ピクセルについて、YUVからRGBへの変換は簡単な線形変換です。あなたはちょうど各ピクセルに同じことを独立して行います。

イメージをRGBに変換したら、テクスチャを作成してイメージを表示できます。テクスチャハンドルを割り当てるにはglGenTextures()、レンダリングコンテキストにテクスチャをバインドするにはglBindTexture()、テクスチャデータをGPUにアップロードするにはglTexImage2D()に電話する必要があります。それをレンダリングするには、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

+0

ファイルにピクセルだけが含まれていると仮定すると、NSDataまたはNSFileHandleを使用してすべてを読み取るだけです。ファイルにサイズ情報などのメタデータが含まれている場合は、標準のCポインタおよび/または構造体演算子を使用してその情報を解釈する必要があります。 –

+0

この回答は間違っています。 MacOS 10.2以降では、すべてのAppleシステムがYUVデータを直接ロードして表示できるOpenGL拡張をサポートしています。詳細は「GL_YCBCR_422_APPLE」を検索してください。この拡張機能を使用すると、データがどこかに(ソフトウェアのドライバ、ハードウェアのGPUなどで)変換されるかどうかはわかりません(GPUがそれを変換しているとき、私を信じて、以上1000%以上) – Mecki

6

Adam Rosenfieldのコメントは不適切です。 Macでは、APPLE_ycbcr_422拡張子に指定されているように、GL_YCBCR_422_APPLEテクスチャ形式を使用してYCbCr(YUVに相当するデジタル)テクスチャを表示できます。

8

これは、CCDカメラからキャプチャしたYUVフレームで行いました。残念ながら、さまざまなYUV形式があります。アップルがGL_YCBCR_422_APPLEテクスチャ形式で使用しているものは、技術的に2VUY422だと私は信じている。2VUY422にIIDCのFireWireカメラによって生成されたYUV422フレームから画像を変換するために、私は次のように使用しました:YUVビデオソースの効率的な表示のために

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); 
    } 
} 

、あなたは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(); 
+0

ありがとうたくさんのbrad – ReachConnection

関連する問題