OpenGL glReadPixels()에서 가져온 RGB 프레임을 YUV 프레임으로 변환하고 YUV 프레임을 파일 (.yuv)에 쓰려고합니다. 나중에 named_pipe에 FFMPEG의 입력으로 쓰고 싶지만 지금은 파일에 쓰고 YUV 이미지 뷰어를 사용하여 이미지 결과를보고 싶습니다. 그래서 지금은 "글쓰기"를 무시하십시오.C/C++에서 YUV 이미지 프레임을 쓸 때의 문제
이YUV 이미지 뷰어 소프트웨어에 표시된 프레임의 수는 항상 내가 내 프로그램에서 선언 된 프레임 수의 1/3 :
내 코드를 실행 한 후, 나는 다음과 같은 오류가 발생했습니다. fps를 10으로 선언하면 3 프레임 만 볼 수 있습니다. fps를 30으로 선언하면 10 프레임 만 볼 수있었습니다. 그러나 텍스트 편집기에서 파일을 볼 때 "FRAME"이라는 단어가 파일에 올바르게 인쇄되어 있습니다. 다음은 출력 예입니다. http://www.bobdanani.net/image.yuv올바른 이미지를 볼 수 없지만 녹색, 파란색, 노란색 및 검은 색 픽셀이 왜곡되어 있습니다.
에서 YUV 형식에 대해 읽어보십시오. 이 변환 방법은 상당히 비효율적이며 나중에 최적화 할 수 있습니다. 이제는이 순진한 방식으로 작업하고 이미지가 제대로 표시되도록하고 싶습니다.
int frameCounter = 1;
int windowWidth = 0, windowHeight = 0;
unsigned char *yuvBuffer;
unsigned long bufferLength = 0;
unsigned long frameLength = 0;
int fps = 10;
void display(void) {
/* clear the color buffers */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* DRAW some OPENGL animation, i.e. cube, sphere, etc
.......
.......
*/
glutSwapBuffers();
if ((frameCounter % fps) == 1){
bufferLength = 0;
windowWidth = glutGet(GLUT_WINDOW_WIDTH);
windowHeight = glutGet (GLUT_WINDOW_HEIGHT);
frameLength = (long) (windowWidth * windowHeight * 1.5 * fps) + 100; // YUV 420 length (width*height*1.5) + header length
yuvBuffer = new unsigned char[frameLength];
write_yuv_frame_header();
}
write_yuv_frame();
frameCounter = (frameCounter % fps) + 1;
if ((frameCounter % fps) == 1){
snprintf(filename, 100, "out/image-%d.yuv", seq_num);
ofstream out(filename, ios::out | ios::binary);
if(!out) {
cout << "Cannot open file.\n";
}
out.write (reinterpret_cast<char*> (yuvBuffer), bufferLength);
out.close();
bufferLength = 0;
delete[] yuvBuffer;
}
}
void write_yuv_frame_header(){
char *yuvHeader = new char[100];
sprintf (yuvHeader, "YUV4MPEG2 W%d H%d F%d:1 Ip A0:0 C420mpeg2 XYSCSS=420MPEG2\n", windowWidth, windowHeight, fps);
memcpy ((char*)yuvBuffer + bufferLength, yuvHeader, strlen(yuvHeader));
bufferLength += strlen (yuvHeader);
delete (yuvHeader);
}
void write_yuv_frame() {
int width = glutGet(GLUT_WINDOW_WIDTH);
int height = glutGet(GLUT_WINDOW_HEIGHT);
memcpy ((void*) (yuvBuffer+bufferLength), (void*) "FRAME\n", 6);
bufferLength +=6;
long length = windowWidth * windowHeight;
long yuv420FrameLength = (float)length * 1.5;
long lengthRGB = length * 3;
unsigned char *rgb = (unsigned char *) malloc(lengthRGB * sizeof(unsigned char));
unsigned char *yuvdest = (unsigned char *) malloc(yuv420FrameLength * sizeof(unsigned char));
glReadPixels(0, 0, windowWidth, windowHeight, GL_RGB, GL_UNSIGNED_BYTE, rgb);
int r, g, b, y, u, v, ypos, upos, vpos;
for (int j = 0; j < windowHeight; ++j){
for (int i = 0; i < windowWidth; ++i){
r = (int)rgb[(j * windowWidth + i) * 3 + 0];
g = (int)rgb[(j * windowWidth + i) * 3 + 1];
b = (int)rgb[(j * windowWidth + i) * 3 + 2];
y = (int)(r * 0.257 + g * 0.504 + b * 0.098) + 16;
u = (int)(r * 0.439 + g * -0.368 + b * -0.071) + 128;
v = (int)(r * -0.148 + g * -0.291 + b * 0.439 + 128);
ypos = j * windowWidth + i;
upos = (j/2) * (windowWidth/2) + i/2 + length;
vpos = (j/2) * (windowWidth/2) + i/2 + length + length/4;
yuvdest[ypos] = y;
yuvdest[upos] = u;
yuvdest[vpos] = v;
}
}
memcpy ((void*) (yuvBuffer + bufferLength), (void*)yuvdest, yuv420FrameLength);
bufferLength += yuv420FrameLength;
free (yuvdest);
free (rgb);
}
이것은 매우 기본적인 접근 방법이며 나중에 변환 알고리즘을 최적화 할 수 있습니다. 누구나 내 접근 방식에서 잘못된 점을 말해 줄 수 있습니까? 내 생각 엔 unsigned char * 데이터를 char * 데이터로 변환했기 때문에 outstream.write() 호출과 관련된 문제가 데이터 정확도를 잃을 수 있다는 것입니다. 하지만 char *로 캐스팅하지 않으면 컴파일 오류가 발생합니다. 그러나 이것이 왜 출력 프레임이 손상되었는지 (총 프레임 수의 1/3에 해당) 설명하지 못합니다.
해결 했습니까? –