Я пытаюсь сделать фреймы захваченными и преобразованными из видео, используя ffmpeg, в текстуру OpenGL, которая будет помещена в квадрат. Я довольно сильно измучил Google и не нашел ответа, ну, я нашел ответы, но никто из них, похоже, не работал.
В основном, я использую avcodec_decode_video2()
для декодирования фрейма, а затем sws_scale()
для преобразования фрейма в RGB, а затем glTexSubImage2D()
для создания текстуры openGL, но не может заставить ничего работать.
Я убедился, что "целевой" AVFrame имеет мощность 2 измерения в настройке контекста SWS. Вот мой код:
SwsContext *img_convert_ctx = sws_getContext(pCodecCtx->width,
pCodecCtx->height, pCodecCtx->pix_fmt, 512,
256, PIX_FMT_RGB24, SWS_BICUBIC, NULL,
NULL, NULL);
//While still frames to read
while(av_read_frame(pFormatCtx, &packet)>=0) {
glClear(GL_COLOR_BUFFER_BIT);
//If the packet is from the video stream
if(packet.stream_index == videoStream) {
//Decode the video
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
//If we got a frame then convert it and put it into RGB buffer
if(frameFinished) {
printf("frame finished: %i\n", number);
sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
glBindTexture(GL_TEXTURE_2D, texture);
//gluBuild2DMipmaps(GL_TEXTURE_2D, 3, pCodecCtx->width, pCodecCtx->height, GL_RGB, GL_UNSIGNED_INT, pFrameRGB->data);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, 512, 256, GL_RGB, GL_UNSIGNED_BYTE, pFrameRGB->data[0]);
SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, number);
number++;
}
}
glColor3f(1,1,1);
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
glTexCoord2f(0,1);
glVertex3f(0,0,0);
glTexCoord2f(1,1);
glVertex3f(pCodecCtx->width,0,0);
glTexCoord2f(1,0);
glVertex3f(pCodecCtx->width, pCodecCtx->height,0);
glTexCoord2f(0,0);
glVertex3f(0,pCodecCtx->height,0);
glEnd();
Как вы можете видеть в этом коде, я также сохраняю фреймы в файлах .ppm, чтобы убедиться, что они действительно рендеринга, каковы они.
Используемый файл -.wmv на 854x480, может ли это быть проблемой? Тот факт, что я просто говорю ему идти 512x256?
P.S. Я рассмотрел этот вопрос о переполнении стека, но это не помогло.
Кроме того, у меня есть glEnable(GL_TEXTURE_2D)
, и он протестировал его, просто загрузив его в нормальный BMP.
ИЗМЕНИТЬ
Теперь я получаю изображение на экране, но это искаженный беспорядок, я предполагаю, что что-то делать с изменением вещей до степени 2 (в декоде, swscontext
и gluBuild2DMipmaps
, как показано в мой код). Я обычно почти точно такой же код, как показано выше, только я изменил glTexSubImage2D
на gluBuild2DMipmaps
и изменил типы на GL_RGBA
.
Вот как выглядит рамка:
ИЗМЕНИТЬ СНОВА
Только что понял, что я не показал код для настройки pFrameRGB:
//Allocate video frame for 24bit RGB that we convert to.
AVFrame *pFrameRGB;
pFrameRGB = avcodec_alloc_frame();
if(pFrameRGB == NULL) {
return -1;
}
//Allocate memory for the raw data we get when converting.
uint8_t *buffer;
int numBytes;
numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
buffer = (uint8_t *) av_malloc(numBytes*sizeof(uint8_t));
//Associate frame with our buffer
avpicture_fill((AVPicture *) pFrameRGB, buffer, PIX_FMT_RGB24,
pCodecCtx->width, pCodecCtx->height);
Теперь, когда я изменил PixelFormat
в avgpicture_get_size
на PIX_FMT_RGB24
, я сделал это в swscontext
, а также изменил gluBuild2DMipmaps
на GL_RGB
, и я получу немного лучшее изображение, но оно похоже, что я все еще не хватает строк, и он все еще немного растягивается:
Другое Редактирование
После того, как мы посоветовали Macke и передали фактическое разрешение OpenGL, я получаю фреймы почти правильно, но все еще немного перекошен и черно-белый, также он получает всего 6 кадров в секунду, а не 110 кадров в секунду:
P.S.
У меня есть функция, чтобы сохранить кадры для изображения после sws_scale()
, и они выходят отлично, как цвет и все, что-то в OGL делает его B & W.
ПОСЛЕДНИЙ РЕДАКТИРОВАТЬ
Рабочая! Хорошо, теперь у меня это работает, в основном я не откладываю текстуру до мощности 2 и просто использую разрешение видео.
Я получил текстуру, которая появляется правильно с удачной предпосылкой правильного glPixelStorei()
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
Кроме того, если у кого-то еще есть subimage()
, показывающий пустую проблему, такую как я, вам нужно заполнить текстуру хотя бы один раз с помощью glTexImage2D()
, и поэтому я использую ее один раз в цикле, а затем использую glTexSubImage2D()
после этого.
Спасибо Macke и datenwolf за вашу помощь.