2009-07-03 2 views
1

샘플 원시 YUV 파일을 취하여 코코아 OpenGL 프로그램에 표시하는 프로그램을 작성하는 작업이 할당되었습니다.코코아 OpenGL 프로그램에서 원시 YUV 프레임을 표시하는 방법

저는 직장에서 인턴입니다. 시작하는 방법이 거의 또는 전혀 없습니다. 나는 위키 피 디아 &에 대한 기사를 YUV에서 읽었지만 원시 YUV 파일을 열고 데이터를 추출하여 RGB로 변환하여보기 창에 표시하는 방법에 대한 좋은 소스 코드를 찾을 수 없었다.

는 기본적으로, 나는 - 어떻게 RGB 색 공간을 표시 - 어떻게 RGB 색 공간 에 YUV 데이터를 변환하기 - 어떻게 샘플 YUV 파일 에서 YUV 데이터를 추출하는 작업 의 다음과 같은 측면에 도움이 필요 OpenGL에서. (시간이 지나면 알아낼 수있을 것 같지만 처음 두 점에 대해서는 도움이 필요합니다.)

클래스를 사용 하시거나 YUV 그래픽/비디오에 대해 배울 수있는 곳을 가르쳐주십시오. 디스플레이

답변

1

이 답변은 정확하지 않습니다, 다른 답변 및 의견을 참조하십시오. 후손을위한 원판 답변.


당신은 직접 표시 할 수 없습니다. RGB 텍스처로 변환해야합니다. Wikipedia에서 수집 한 것처럼 YUV 색상 공간에는 다양한 변형이 있습니다. 올바른 것을 사용하고 있는지 확인하십시오.

각 픽셀에 대해 YUV에서 RGB 로의 변환은 직선적 인 선형 변환입니다. 당신은 각 픽셀에 독립적으로 똑같은 일을합니다.

일단 이미지를 RGB로 변환하면 텍스처를 만들어서 이미지를 표시 할 수 있습니다. 텍스처 핸들을 할당하려면 glGenTextures()으로, 렌더 컨텍스트에 텍스처를 바인딩하려면 glBindTexture()으로, 텍스처 데이터를 GPU에 업로드하려면 glTexImage2D()으로 호출해야합니다. 렌더링하려면 glBindTexture()을 다시 호출하고 텍스처 좌표가 올바르게 설정된 쿼드 렌더링을 수행합니다.

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)를 호출하는 것을 잊지 마세요 :

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

렌더링합니다.

+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 형식이 있습니다. Apple이 GL_YCBCR_422_APPLE 텍스처 형식으로 사용하는 것이 기술적으로 2VUY422라고 생각합니다.2VUY422에 IIDC 파이어 와이어 카메라에 의해 생성 된 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

관련 문제