IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

SDL Discussion :

Incrustation sur video (SDL_Overlay) -> conversion RGB->YUV


Sujet :

SDL

  1. #1
    Membre à l'essai
    Inscrit en
    Mai 2006
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 18
    Points : 10
    Points
    10
    Par défaut Incrustation sur video (SDL_Overlay) -> conversion RGB->YUV
    Bonjour,


    Je développe une application qui va chercher un flux rtsp avec gstreamer et l'affiche grace au sdlvideosink. J'ai modifié le sdlvideosink afin qu'il fasse ce que je veux. Or, gstreamer met le flux vidéo dans une structure de type SDL_Overlay.

    Problème : Existe-t-il une fonction (ou une bibliothèque contenant une fonction) qui puisse effectuer des blit sur des Overlay ?
    Si oui, pas la peine de lire la suite !

    En attendant, j'ai codé une fonction qui le fait. Le premier souci est que, comme l'Overlay est en YUV et ma surface source en RGB, il faut la convertir. Vu qu'il existe 25 types de YUV, j'ai testé toutes les conversions jusqu'à tomber sur une qui marche pas trop mal (au niveau des couleurs) : celle de GIMP. => Les couleurs ne sont pas exactes (rouge trop foncé, bleu trop clair)

    De plus, je modifie la taille de l'Overlay par rapport à sa taille d'origine (uniquement en X), ce qui ajoute un coefficient de dilatation horizontal (appelé fHCoeff dans le code ci-dessous). Et ceci inflige des effets moches sur les formes (cassures dans les droites, bavures, surtout dans les couleurs rouges).

    Enfin, comme c'est moi qui l'ai codé, c'est entièrement du soft, et donc ça bouffe des ressources processeurs trop importantes (je ne peux pas me permettre de blitter sur toute la vidéo, ça rame).

    S'il n'existe pas d'alternative à le faire à la main, serait-il possible de jeter un oeil à mon code de conversion RGB->YUV svp ?

    Voici le code de la (seule) version que j'ai réussi à faire marcher :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    void apply_surface_Overlay (int x,int y,SDL_Surface *source, SDL_Overlay *destination)
    {
    	if(source == NULL)
    		return;
     
    	SDL_LockSurface(source);
    	SDL_LockYUVOverlay(destination);
    	int i,j;
     
    	int nIndexPixelY, nIndexPixelU, nIndexPixelV;
    	BOOL bColorKey = (source->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY;
    	BOOL bAlpha = (source->flags & SDL_SRCALPHA) == SDL_SRCALPHA;
    	float tY, tU, tV;
    	float fCoeff; // Coefficient d'alpha
    	double fR, fG, fB;
    	guint32 nPixel;
     
    	for(j= 0; j < source->h; j ++)
    	{
    		for(i = 0; i < source->w; i++)
    		{
    			if(i + x > sH.sdlvideosink->rect.x && i + x < sH.sdlvideosink->rect.x + sH.sdlvideosink->rect.w
    			&& j + y > sH.sdlvideosink->rect.y && j + y < sH.sdlvideosink->rect.y + sH.sdlvideosink->rect.h)
    			{
    				nPixel = *(((guint32*)source->pixels) + i + j * source->w);
    				fR = (RMASK & nPixel);
    				fG = (GMASK & nPixel)>>8;
    				fB = (BMASK & nPixel)>>16;
     
    				if(bColorKey &&  source->format->colorkey == (nPixel & 0x00FFFFFF))
    				{
    				}
    				else
    				{
    					nIndexPixelY = (x+i - sH.sdlvideosink->rect.x)*sH.fHCoeff  + (j + y - sH.sdlvideosink->rect.y) * I420_Y_ROWSTRIDE (sH.sdlvideosink->width);
    					nIndexPixelU = (x+i - sH.sdlvideosink->rect.x)*sH.fHCoeff/2 + ((j + y - sH.sdlvideosink->rect.y)/2) * I420_U_ROWSTRIDE (sH.sdlvideosink->width);
    					nIndexPixelV = (x+i - sH.sdlvideosink->rect.x)*sH.fHCoeff/2 + ((j + y - sH.sdlvideosink->rect.y)/2) * I420_V_ROWSTRIDE (sH.sdlvideosink->width);
     
    					// TODO : modifier par les plus proches voisins (index à modifier, prendre le 4 voisinage au moins)
    					tY = ( 0.2990009 * fR + 0.5870019 * fG + 0.1139970 * fB);
    					tU = (- 0.1690005 * fR - 0.3310011 * fG + 0.5000165 * fB + 128);
    					tV = ( 0.4999993 * fR - 0.4190013 * fG - 0.0809979 * fB + 128);
     
    					tY = ((tY>=0)?((tY<=255)?tY:255):0);
    					tU = ((tU>=0)?((tU<=255)?tU:255):0);
    					tV = ((tV>=0)?((tV<=255)?tV:255):0);
     
    					if(!bAlpha || (bAlpha && source->format->alpha == 0xFF)) // AUCUNE TRANSPARENCE A GERER
    					{
    						destination->pixels[0][nIndexPixelY] = (guint8)tY;
    						destination->pixels[1][nIndexPixelU] = (guint8)tU;
    						destination->pixels[2][nIndexPixelV] = (guint8)tV;
    					}
    					else // TRANSPARENCE
    					{
    						fCoeff = (source->format->alpha / (float)(0xFF));
     
    						tY = fCoeff * tY + (1-fCoeff)*destination->pixels[0][nIndexPixelY];
    						tU = fCoeff * tU + (1-fCoeff)*destination->pixels[1][nIndexPixelU];
    						tV = fCoeff * tV + (1-fCoeff)*destination->pixels[2][nIndexPixelV];
     
    						tY = ((tY>=0)?((tY<=255)?tY:255):0);
    						tU = ((tU>=0)?((tU<=255)?tU:255):0);
    						tV = ((tV>=0)?((tV<=255)?tV:255):0);
     
    						destination->pixels[0][nIndexPixelY] = (guint8)tY;
    						destination->pixels[1][nIndexPixelU] = (guint8)tU;
    						destination->pixels[2][nIndexPixelV] = (guint8)tV;
     
    					}
    				}
    			}
    		}
     
    	}
    	SDL_UnlockSurface(source);
    	SDL_UnlockYUVOverlay(destination);
    }
    Voici une autre version, qui fonctionne dans l'autre sens (calcul des coordonnées directement sur l'overlay), mais qui ne marche pas mieux (même pire) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
     
    void apply_surface_Overlay (int x,int y,SDL_Surface *source, SDL_Overlay *destination)
    {
    	if(source == NULL)
    		return;
     
    	SDL_LockSurface(source);
    	SDL_LockYUVOverlay(destination);
    	int i,j;
            int nXMin, nXMax, nYMin, nYMax; // bornes de la zone de destination concernée par le blit
    	nXMin = (int)(floor((x - sH.sdlvideosink->rect.x)*sH.fHCoeff));
    	nXMax = (int)(ceil((x + source->w - sH.sdlvideosink->rect.x)*sH.fHCoeff));
    	nYMin = (int)(floor(y - sH.sdlvideosink->rect.y));
    	nYMax = (int)(ceil(y + source->h - sH.sdlvideosink->rect.y));
    	float srcx, srcy;
    	double fR, fG, fB, fR2, fG2, fB2;
    	Uint32 nPixel, nPixel2;
     
    	for(i = nXMin; i < nXMax; i++)
    	{
    		for(j = nYMin; j < nYMax; j++)
    		{
    			if(i >= 0 && j >= 0 && i < sH.sdlvideosink->rect.w && j < sH.sdlvideosink->rect.h)
    			{
    				srcx = (i / sH.fHCoeff) - x + sH.sdlvideosink->rect.x;
    				srcy = j - y + sH.sdlvideosink->rect.y;
     
    				nPixel = *(((guint32*)source->pixels) + (int)floor(srcx) + (int)srcy * source->w);
    				nPixel2 = *(((guint32*)source->pixels) + (int)floor(srcx) + 1 + (int)srcy * source->w);
     
    				// récup des valeurs
    				fR = (RMASK & nPixel);
    				fG = (GMASK & nPixel)>>8;
    				fB = (BMASK & nPixel)>>16;
    				// récup des valeurs
    				fR2 = (RMASK & nPixel2);
    				fG2 = (GMASK & nPixel2)>>8;
    				fB2 = (BMASK & nPixel2)>>16;
     
    				// pourcentage
    				fR = (srcx - floor(srcx)) * fR + ( floor(srcx)+1 - srcx) * fR2;
    				fG = (srcx - floor(srcx)) * fG + ( floor(srcx)+1 - srcx) * fG2;
    				fB = (srcx - floor(srcx)) * fB + ( floor(srcx)+1 - srcx) * fB2;
     
    				if(bColorKey &&  source->format->colorkey == (nPixel & 0x00FFFFFF))
    				{
    				}
    				else
    				{
    					nIndexPixelY = i + j * I420_Y_ROWSTRIDE (sH.sdlvideosink->width);
    					nIndexPixelU = i/2 + j/2 * I420_U_ROWSTRIDE (sH.sdlvideosink->width);
    					nIndexPixelV = i/2 + j/2 * I420_V_ROWSTRIDE (sH.sdlvideosink->width);
     
    					tY = ( 0.2990009 * fR + 0.5870019 * fG + 0.1139970 * fB);
    					tU = (- 0.1690005 * fR - 0.3310011 * fG + 0.5000165 * fB + 128);
    					tV = ( 0.4999993 * fR - 0.4190013 * fG - 0.0809979 * fB + 128);
     
    					tY = ((tY>=0)?((tY<=255)?tY:255):0);
    					tU = ((tU>=0)?((tU<=255)?tU:255):0);
    					tV = ((tV>=0)?((tV<=255)?tV:255):0);
     
     
    					if(!bAlpha || (bAlpha && source->format->alpha == 0xFF)) // AUCUNE TRANSPARENCE A GERER
    					{
    						destination->pixels[0][nIndexPixelY] = (guint8)tY;
    						destination->pixels[1][nIndexPixelU] = (guint8)tU;
    						destination->pixels[2][nIndexPixelV] = (guint8)tV;
    					}
    					else // TRANSPARENCE
    					{
     
    						tY = fCoeff * tY + (1-fCoeff)*destination->pixels[0][nIndexPixelY];
    						tU = fCoeff * tU + (1-fCoeff)*destination->pixels[1][nIndexPixelU];
    						tV = fCoeff * tV + (1-fCoeff)*destination->pixels[2][nIndexPixelV];
     
     
    						destination->pixels[0][nIndexPixelY] = (guint8)tY;
    						destination->pixels[1][nIndexPixelU] = (guint8)tU;
    						destination->pixels[2][nIndexPixelV] = (guint8)tV;
    					}	
    				}
     
    			}
    		}
    	}
    	SDL_UnlockSurface(source);
    	SDL_UnlockYUVOverlay(destination);
    }
    Je vais éditer ce message afin de mettre des screenshots de l'effet que mon incrustation produit. EDIT :


    En tout cas merci d'avance à celui (ou celle) qui aura lu jusque là

  2. #2
    Membre expérimenté
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Points : 1 452
    Points
    1 452
    Par défaut
    Salut,

    Ce que tu veux c'est convertir du RGB en YUV?
    Ici il y a du code intéressant. (apparement)

  3. #3
    Membre à l'essai
    Inscrit en
    Mai 2006
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    Merci pour ce lien, je suis en train d'y jeter un coup d'oeil pour le blit.


    En tout cas pour le calcul RGB->YUV, sa matrice est pire que la mienne (voir la comparaison des couleurs) :

    -> le blanc (que je n'ai aps représenté sur l'image, n'est même pas blanc, il est gris. De toute façon ça peut se voir aux coefficients, si R = G = B = 255, ça ne donne pas blanc.


    EDIT : Le blit fonctionne bien, pour une application à une echelle de 100%. Mais ça ne corrige pas les défauts que j'ai.

    Quelqu'un aurait-il une autre idée ou un autre lien magique ?

  4. #4
    Membre expérimenté
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Points : 1 452
    Points
    1 452
    Par défaut
    Pour le zoom il y a plein de fonctions sur internet, notamment le célèbre rotozoom de SDL_gfx.
    Sinon, c'est intrigant cette histoire de conversion RGB->YUV, il devrait bien exister une solution universelle!!

    A propos de ton problème, que veux tu faire exactement? D'après ce que j'ai compris, le flux est chargé dans une structure SDL_Overlay, mais pourquoi as-tu besoin de faire des blits de SDL_Surface vers le YUV?

    En tout cas bonne chance

  5. #5
    Membre à l'essai
    Inscrit en
    Mai 2006
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    Citation Envoyé par coyotte507 Voir le message
    A propos de ton problème, que veux tu faire exactement? D'après ce que j'ai compris, le flux est chargé dans une structure SDL_Overlay, mais pourquoi as-tu besoin de faire des blits de SDL_Surface vers le YUV?
    Et bien pour incruster dans la vidéo pardi !

    Tu ferais comment toi ? Genre, si c'est une vidéo et que tu veux incruster l'heure, par exemple ?
    -> time() -> sdl_ttf -> blit @ vidéo, non ? Or, chez moi la vidéo est obligatoirement sur un SDL_Overlay, donc pas de blit hardware... a priori.

    J'ai pensé au rotozoom tout à l'heure, mais j'avais pas encore envisagé de faire dans ce sens (c'est à dire réduire mon image source pour l'incruster ensuite sur la vidéo, qui sera, elle-même agrandie). Je teste ça demain.

    PS : pour info, le flux vidéo est 704x576, que j'affiche en 728x576 dans une fenêtre SDL plein écran en 800x600.

  6. #6
    Membre à l'essai
    Inscrit en
    Mai 2006
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    Et bien j'ai testé en faisant un rotozoom (et même un sge_transform_surface), les résultats sont, comme je pouvais l'imaginer, de la même nature :

    La réduction de l'image source (même en activant l'AA sur les transformations) provoque une perte d'informations qui se voit lors de l'affichage sur l'overlay. Ce qui provoque le même type de dégradations (coupures), et un effet de flou supplémentaire (qui n'est pas présent lorsqu'on fait la transformation à la volée).

    Je pense que je ne pourrais pas avoir une qualité meilleure si je garde mon coefficient de déformation de l'image.

    Il reste cependant le problème du RGB->YUV qui donne à la fois des couleurs fausses et des formes erronnées !

  7. #7
    Membre expérimenté
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Points : 1 452
    Points
    1 452
    Par défaut
    Et pourquoi ne pas afficher l'overlay via SDL_DisplayYUVOverlay, et ensuite blitter l'heure sur la surface de display? Le zoom de l'overlay se fait automatiquement, il y a juste à gérer le zoom de ta surface..

    Genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    mon_overlay = SDL_CreateYUVOverlay(largeur, hauteur, format, screen);
    ....
    SDL_DisplayYUVOverlay(mon_overlay, &pos_overlay);
    SDL_BlitSurface(horloge, NULL, screen, &pos_horloge);
    De cette manière il n'y a même pas besoin d'effectuer la conversion RGBYUV, il faut juste éventuellement faire un zoom de l'horloge.

  8. #8
    Membre à l'essai
    Inscrit en
    Mai 2006
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    J'y avais pensé, mais cela crée un clignotement : SDL_DisplayYUVOverlay a le même effet que SDL_UpdateRect : il affiche directement le contenu, du coup, il affiche une fois la vidéo sans l'incrust, une fois avec (après le SDL_UpdateRect du screen).
    Et rebelote à l'arrivée de l'image suivante de la vidéo sur overlay...

Discussions similaires

  1. Extraction texte sur video
    Par nvincent dans le forum Vidéo
    Réponses: 1
    Dernier message: 07/09/2007, 12h03
  2. Conversion RGB <> HEX
    Par Tchupacabra dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 28/08/2007, 10h10
  3. Diverses questions sur les fonctions de conversion
    Par Louis-Guillaume Morand dans le forum Access
    Réponses: 12
    Dernier message: 27/12/2006, 10h56
  4. Conversion RGB vers YCbCr et autres
    Par progfou dans le forum Traitement d'images
    Réponses: 8
    Dernier message: 12/07/2006, 08h53
  5. Conversion RGB To TLS
    Par Catbull dans le forum Algorithmes et structures de données
    Réponses: 7
    Dernier message: 18/12/2003, 15h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo