Cocoa OpenGL プログラムで生の YUV フレームを表示する方法
質問
私は、サンプルの生の YUV ファイルを取得し、それを Cocoa OpenGL プログラムで表示するプログラムを作成するタスクを割り当てられました。
私は職場でインターンをしていますが、どのように始めればよいのかまったくわかりません。YUV に関するウィキペディアや記事を読んでいましたが、生の YUV ファイルを開いてデータを抽出し、RGB に変換してビュー ウィンドウに表示する方法に関する適切なソース コードが見つかりませんでした。
基本的に、タスクの以下の側面についてサポートが必要です - サンプルYUVファイルからYUVデータを抽出する方法 - YUVデータをRGBカラースペースに変換する方法 - OpenGLにRGBカラースペースを表示する方法。(これは時間が経てばわかると思いますが、最初の 2 つの点については本当に助けが必要です)
使用するクラスを教えてください、または YUV グラフィック/ビデオ表示について学べる場所を教えてください
解決
この答えが正解ではない、他の回答やコメントを参照してください。オリジナルの答えは、後世のために、以下の左。の
<時間><ストライキ>あなたはそれを直接表示することができません。ストライキ>あなたはRGBテクスチャに変換する必要があります。あなたはウィキペディアするから収集しているかもしれませんが、YUV色空間上のバリエーションの束があります。あなたは右のいずれかを使用していることを確認します。
各画素について、RGBへのYUVの変換は単純線形変換です。あなただけの独立して各画素に同じことを行う。
あなたは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)
を呼び出すことを忘れないでください。
他のヒント
CCD カメラからキャプチャした YUV フレームを使用してこれを実行しました。残念ながら、さまざまな YUV 形式が多数あります。Apple が使用しているものだと思います。 GL_YCBCR_422_APPLE
テクスチャ形式は技術的には 2VUY422 です。IIDC Firewire カメラによって生成された 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 のクライアント ストレージ拡張機能, 、次のようなものを使用して設定できます。
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();
アダム・ローゼンフィールドのコメントは間違っています。Mac では、 GL_YCBCR_422_APPLE
で指定されているテクスチャ形式 APPLE_ycbcr_422 拡大。