2009-07-09 40 views
11

Tôi gặp sự cố khi hiển thị tệp YUV thô ở định dạng NV12.Cần trợ giúp với màn hình YUV trong OpenGl

Tôi có thể hiển thị khung được chọn, tuy nhiên, nó vẫn chủ yếu là màu đen và trắng với các sắc thái nhất định của màu hồng và màu xanh lá cây.

Sau đây là cách đầu ra của tôi trông giống như alt text http://i32.tinypic.com/hv0vih.png

Anyways, đây là cách chương trình của tôi hoạt động. (Điều này được thực hiện trong ca cao/mục tiêu-c, nhưng tôi cần lời khuyên của chuyên gia về thuật toán chương trình, không phải theo cú pháp.)

Trước khi thực hiện chương trình, tệp YUV được lưu trữ trong tệp nhị phân có tên là "test.yuv" . Tệp ở định dạng NV12, có nghĩa là kế hoạch Y được lưu trước, sau đó kế hoạch UV được xen kẽ. Khai thác tập tin của tôi không có vấn đề bởi vì tôi đã làm rất nhiều thử nghiệm trên nó.

Trong bắt đầu, tôi tạo ra một bảng tra cứu mà sẽ chuyển đổi nhị phân/8 cắn/A byte/chars vào tôn trọng Y, U, V phao đánh giá cao

Đối với máy bay Y đây là mã của tôi

-(void)createLookupTableY //creates a lookup table for converting a single byte into a float between 0 and 1 
{ 
    NSLog(@"YUVFrame: createLookupTableY"); 
    lookupTableY = new float [256]; 

    for (int i = 0; i < 256; i++) 
    { 
     lookupTableY[i] = (float) i /255; 
     //NSLog(@"lookupTableY[%d]: %f",i,lookupTableY[i]);//prints out the value of each float 
    } 
} 

U Plane tra cứu bảng

-(void)createLookupTableU //creates a lookup table for converting a single byte into a float between 0 and 1 
{ 
    NSLog(@"YUVFrame: createLookupTableU"); 
    lookupTableU = new float [256]; 

    for (int i = 0; i < 256; i++) 
    { 
     lookupTableU[i] = -0.436 + (float) i/255* (0.436*2); 
     NSLog(@"lookupTableU[%d]: %f",i,lookupTableU[i]);//prints out the value of each float 
    } 
} 

Và bảng V lookup

-(void)createLookupTableV //creates a lookup table for converting a single byte into a float between 0 and 1 
{ 
    NSLog(@"YUVFrame: createLookupTableV"); 
    lookupTableV = new float [256]; 

    for (int i = 0; i < 256; i++) 
    { 
     lookupTableV[i] = -0.615 + (float) i /255 * (0.615*2); 
     NSLog(@"lookupTableV[%d]: %f",i,lookupTableV[i]);//prints out the value of each float 
    } 
} 

sau thời điểm này, tôi trích xuất các kế hoạch UV Y & và lưu trữ chúng thành hai bộ đệm, yBuffer & uvBuffer

vào thời điểm này, tôi cố gắng để chuyển đổi dữ liệu YUV và lưu trữ nó vào một mảng RGB đệm gọi là " frameImage"

-(void)sortAndConvert//sort the extracted frame data into an array of float 
{ 
    NSLog(@"YUVFrame: sortAndConvert"); 
    int frameImageCounter = 0; 
    int pixelCounter = 0; 
    for (int y = 0; y < YUV_HEIGHT; y++)//traverse through the frame's height 
    { 
     for (int x = 0; x < YUV_WIDTH; x++)//traverse through the frame's width 
     { 

      float Y = lookupTableY [yBuffer [y*YUV_WIDTH + x] ]; 
      float U = lookupTableU [uvBuffer [ ((y/2) * (YUV_WIDTH/2) + (x/2)) * 2 ] ]; 
      float V = lookupTableV [uvBuffer [ ((y/2) * (YUV_WIDTH/2) + (x/2)) * 2 + 1] ]; 

      float RFormula = Y + 1.13983f * V; 
      float GFormula = Y - 0.39465f * U - 0.58060f * V; 
      float BFormula = Y + 2.03211f * U; 

      frameImage [frameImageCounter++] = [self clampValue:RFormula]; 
      frameImage [frameImageCounter++] = [self clampValue:GFormula]; 
      frameImage [frameImageCounter++] = [self clampValue:BFormula]; 

     } 
    } 

} 

sau đó tôi đã cố gắng để vẽ các hình ảnh trong OpenGL

-(void)drawFrame:(int)x 
{ 

    GLuint texture; 

    glGenTextures(1, &texture); 
    glBindTexture(GL_TEXTURE_2D, texture); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, YUV_WIDTH, YUV_HEIGHT, 0, GL_RGB, GL_FLOAT, frameImage); 

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 

    glEnable(GL_TEXTURE_2D); 
    glBindTexture(GL_TEXTURE_2D, texture); 
    glRotatef(180.0f, 1.0f, 0.0f, 0.0f); 

    glBegin(GL_QUADS); 
    glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0); 
    glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0); 
    glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0); 
    glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0); 
    glEnd(); 

    glFlush(); 
} 

rất cơ bản này chương trình của tôi trong một vỏ ốc. về cơ bản tôi đọc các tệp YUV nhị phân, lưu trữ tất cả dữ liệu trong bộ đệm mảng char. sau đó tôi dịch các giá trị này thành giá trị float YUV được kính trọng của chúng.

Đây là nơi tôi nghĩ lỗi có thể là: trong bảng tra cứu Y tôi chuẩn hóa mặt phẳng Y thành [0,1], trong mặt phẳng U, tôi đã chuẩn hóa các giá trị giữa [-0.435,0.436] và trong Mặt phẳng V tôi đã chuẩn hóa nó thành mười sáu [-0,615,0,615]. Tôi đã làm điều này bởi vì đó là những giá trị YUV phạm vi theo wikipedia.

Và công thức YUV đến RGB là công thức tương tự từ Wikipedia. Tôi cũng đã thử nhiều công thức khác, và đây là công thức duy nhất cung cấp cho triển vọng thô của khung. Bất cứ ai cũng có thể mạo hiểm để đoán tại sao chương trình của tôi không hiển thị chính xác dữ liệu khung YUV. Tôi nghĩ rằng đó là một cái gì đó để làm với kỹ thuật tiêu chuẩn hóa của tôi, nhưng nó có vẻ ổn với tôi.

Tôi đã thực hiện rất nhiều thử nghiệm và tôi chắc chắn 100% rằng lỗi gây ra bởi bằng cách tra cứu bảng. Tôi không nghĩ rằng công thức cài đặt của tôi là chính xác.

Lưu ý cho tất cả những người đang đọc điều này.Trong thời gian dài nhất, khung hình của tôi không hiển thị chính xác vì tôi không thể trích xuất dữ liệu khung chính xác.

Khi tôi lần đầu tiên bắt đầu chương trình, tôi đã theo ấn tượng rằng trong một clip của nói 30 khung hình, tất cả 30 Y phẳng dữ liệu ngay lần đầu tiên được ghi trong tệp dữ liệu, theo sau đó bởi dữ liệu ngay mặt phẳng UV.

gì tôi phát hiện ra bằng cách thử và lỗi là cho một tập tin dữ liệu YUV, đặc biệt NV12, các tập tin dữ liệu là được lưu trữ trong thời trang sau

Y (1) UV (1) Y (2) UV (2) ... ...

@nschmidt

tôi đã thay đổi mã của tôi với những gì bạn đề nghị

float U = lookupTableU [uvBuffer [ (y * (YUV_WIDTH/4) + (x/4)) * 2 ] ] 
float V = lookupTableU [uvBuffer [ (y * (YUV_WIDTH/4) + (x/4)) * 2 + 1] ] 

và đây là kết quả tôi nhận được alt text http://i26.tinypic.com/kdtilg.png

đây là dòng in từ bảng điều khiển. tôi in ra các giá trị cho Y, U, V và giá trị RGB đang được dịch và được lưu trữ trên trong mảng frameImage

YUV: [0,658824, -0,022227, -0,045824] RGBFinal: [0.606593,0.694201,0.613655 ]

YUV: [0,643137, -0,022227, -0,045824] RGBFinal: [0.590906,0.678514,0.597969]

YUV: [0,607843, -0,022227, -0,045824] RGBFinal: [0.555612,0.643220,0.562675]

YUV: [0.592157, -0.022227, -0.045824] RGBFinal: [0.539926,0.627534,0.546988]

YUV: [0.643137,0.025647,0.151941] RGBFinal: [0.816324,0.544799,0.695255]

YUV: [0.662745,0.025647,0.151941] RGBFinal: [0.835932,0.564406,0.714863]

YUV: [0,690196 , 0.025647,0.151941] RGBFinal: [0.863383,0.591857,0.742314]

cập nhật 13 Tháng 7 2009

vấn đề cuối cùng đã được giải quyết nhờ sự giới thiệu từ nschmidt. Nó chỉ ra rằng tập tin YUV của tôi đã thực sự ở định dạng YUV 4: 1: 1. Ban đầu tôi đã nói rằng nó ở định dạng YUV NV12. Dù sao, tôi muốn chia sẻ kết quả của tôi với bạn.

Đây là sản lượng

alt text http://i32.tinypic.com/35b9xf8.png

và mã của tôi cho giải mã như sau

 float Y = (float) yBuffer [y*YUV_WIDTH + x] ; 
     float U = (float) uvBuffer [ ((y/2) * (YUV_WIDTH/2) + (x/2)) ] ; 
     float V = (float) uvBuffer [ ((y/2) * (YUV_WIDTH/2) + (x/2)) + UOffset] ; 

     float RFormula = (1.164*(Y-16) + (1.596* (V - 128))); 
     float GFormula = ((1.164 * (Y - 16)) - (0.813 * ((V) - 128)) - (0.391 * ((U) - 128))); 
     float BFormula = ((1.164 * (Y - 16)) + (2.018 * ((U) - 128))); 


     frameImage [frameImageCounter] = (unsigned char)((int)[self clampValue:RFormula]); 
     frameImageCounter ++; 
     frameImage [frameImageCounter] = (unsigned char)((int)[self clampValue:GFormula]); 
     frameImageCounter++; 
     frameImage [frameImageCounter] = (unsigned char)((int) [self clampValue:BFormula]); 
     frameImageCounter++; 



GLuint texture; 

glGenTextures(1, &texture); 
glEnable(GL_TEXTURE_2D); 

glBindTexture(GL_TEXTURE_2D, texture); 
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); 

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, YUV_WIDTH, YUV_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, frameImage); 

//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE_SGIS); 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE_SGIS); 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); 

glRotatef(180.0f, 1.0f, 0.0f, 0.0f); 

glBegin(GL_QUADS); 
glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0); 
glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0); 
glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0); 
glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0); 
glEnd(); 

NSLog(@"YUVFrameView: drawRect complete"); 
glFlush(); 

về cơ bản, tôi đã sử dụng NSData để tách file raw. được lưu trữ trong một bộ đệm mảng char. Để chuyển đổi YUV sang RGB, tôi đã sử dụng công thức trên, sau đó, tôi đã kẹp các giá trị thành [0: 255]. sau đó tôi đã sử dụng 2DTexture trong OpenGL để hiển thị.

Vì vậy, nếu bạn đang chuyển đổi YUV để RGB trong tương lai, sử dụng công thức từ trên cao. Nếu đang sử dụng công thức chuyển đổi YUV sang RGB từ bài trước, thì bạn cần hiển thị kết cấu trong GL_Float từ các giá trị cho RGB được kẹp giữa [0: 1]

Trả lời

8

Tiếp thử :) Tôi nghĩ rằng bạn đang uv đệm không xen kẽ. Dường như giá trị U đến trước và sau đó là mảng giá trị V. Thay đổi các dòng thành

unsigned int voffset = YUV_HEIGHT * YUV_WIDTH/2; 
float U = lookupTableU [uvBuffer [ y * (YUV_WIDTH/2) + x/2] ]; 
float V = lookupTableV [uvBuffer [ voffset + y * (YUV_WIDTH/2) + x/2] ]; 

có thể cho biết đây có phải là trường hợp không.

+0

wow, tôi đã thử nghiệm chương trình của tôi với điều chỉnh của bạn và cuối cùng nó đã hoạt động. cảm ơn rất nhiều man.it chỉ ra rằng bạn đã đúng, máy bay U & V không xen kẽ như tôi đã được bảo. cảm ơn bạn rất nhiều nschmidt. Tôi đang xếp hạng bạn lên – ReachConnection

+0

không thành vấn đề :). cho bản ghi, đoán đầu tiên về định dạng là 4: 1: 1 thực sự không chính xác. Bạn có định dạng 4: 2: 2. Vấn đề thực sự chỉ là dữ liệu của bạn không bị xen kẽ. – nschmidt

+0

@ReachConnection: Ông có thể cho tôi biết những gì [tự clampValue: RFormula]? Chức năng này đang làm tôi đang lên kế hoạch sử dụng mã của bạn để có được UIImage từ YUV422. –

3

Tôi nghĩ bạn đang giải quyết các giá trị U và V không đúng. Thay vì:

float U = lookupTableU [uvBuffer [ ((y/2) * (x/2) + (x/2)) * 2 ] ]; 
float V = lookupTableV [uvBuffer [ ((y/2) * (x/2) + (x/2)) * 2 + 1] ]; 

Nó phải là một cái gì đó dọc theo dòng của

float U = lookupTableU [uvBuffer [ ((y/2) * (YUV_WIDTH/2) + (x/2)) * 2 ] ]; 
float V = lookupTableV [uvBuffer [ ((y/2) * (YUV_WIDTH/2) + (x/2)) * 2 + 1] ]; 
+0

cảm ơn, tôi đã bỏ lỡ lỗi này. tuy nhiên, tôi đã thực hiện các thay đổi và khung hiển thị vẫn chủ yếu là màu đen và trắng, với các sắc thái màu hồng và màu xanh lá cây ở đây và ở đó. – ReachConnection

+0

Tôi chỉ cần thêm một hình ảnh để hiển thị đầu ra của tôi trông như thế nào – ReachConnection

0

Bức tranh trông giống như bạn có 4: Định dạng 1: 1. Bạn nên thay đổi các dòng của mình thành

float U = lookupTableU [uvBuffer [ (y * (YUV_WIDTH/4) + (x/4)) * 2 ] ] 
float V = lookupTableU [uvBuffer [ (y * (YUV_WIDTH/4) + (x/4)) * 2 + 1] ] 

Có thể bạn có thể đăng kết quả để xem, điều gì khác là sai. Tôi thấy thật khó để nghĩ về nó. Sẽ dễ dàng hơn khi tiếp cận điều này lặp đi lặp lại.

Các vấn đề liên quan