J'essaie de rendre des images saisies et converties d'une vidéo à l'aide de ffmpeg en une texture OpenGL à placer sur un quad. J'ai pratiquement épuisé google sans trouver de réponse, enfin j'ai trouvé des réponses mais aucune ne semble avoir fonctionné.
En gros, j'utilise avcodec_decode_video2()
pour décoder la trame et ensuite sws_scale()
pour convertir l'image en RGB et ensuite glTexSubImage2D()
pour créer une texture openGL à partir de celui-ci mais je n'arrive pas à faire fonctionner quoi que ce soit.
Je me suis assuré que l'AVFrame "de destination" avait une puissance de 2 dimensions dans la configuration du contexte SWS. Voici mon code :
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();
Comme vous pouvez le voir dans ce code, j'enregistre également les images dans des fichiers .ppm pour m'assurer qu'elles sont effectivement rendues, ce qui est le cas.
Le fichier utilisé est un .wmv en 854x480, cela pourrait-il être le problème ? Le fait que je lui demande simplement de passer en 512x256 ?
P.S. J'ai regardé ceci Question sur Stack Overflow mais ça n'a pas aidé.
Aussi, j'ai glEnable(GL_TEXTURE_2D)
et je l'ai testé en chargeant simplement un fichier bmp normal.
EDIT
J'obtiens une image sur l'écran maintenant mais c'est un désordre confus, je suppose que quelque chose à voir avec le changement des choses à une puissance de 2 (dans le décodage), swscontext
y gluBuild2DMipmaps
comme indiqué dans mon code). En général, j'utilise presque exactement le même code que celui présenté ci-dessus, sauf que j'ai modifié glTexSubImage2D
a gluBuild2DMipmaps
et changé les types en GL_RGBA
.
Voici à quoi ressemble le cadre :
EDIT ENCORE
Je viens de réaliser que je n'ai pas montré le code de la configuration de 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);
Maintenant que j'ai changé le PixelFormat
sur avgpicture_get_size
a PIX_FMT_RGB24
J'ai fait ça en SwsContext
également et a changé GluBuild2DMipmaps
a GL_RGB
et j'obtiens une image légèrement meilleure, mais on dirait qu'il manque encore des lignes et qu'elle est encore un peu étirée :
Une autre édition
Après avoir suivi les conseils de Macke et transmis la résolution réelle à OpenGL, j'obtiens des images presque correctes mais toujours un peu déformées et en noir et blanc, et je n'obtiens que 6 images par seconde au lieu de 110 :
P.S.
J'ai une fonction pour sauvegarder les cadres dans une image après sws_scale()
et elles sortent bien en couleur et tout, donc quelque chose dans OGL les rend en N&B.
DERNIER ÉDIT
Le travail ! Ok, j'ai réussi à le faire fonctionner maintenant. En fait, je n'ai pas rempli la texture à la puissance 2 et j'ai utilisé la résolution de la vidéo.
J'ai réussi à faire apparaître la texture correctement avec une estimation chanceuse du glPixelStorei() correct.
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
Aussi, si quelqu'un d'autre a le subimage()
montrant un problème de blanc comme moi, vous devez remplir la texture au moins une fois avec glTexImage2D()
et donc je l'utilise une fois dans la boucle et ensuite j'utilise glTexSubImage2D()
après cela.
Merci Macke et datenwolf pour toute votre aide.