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 :
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 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); }
Je vais éditer ce message afin de mettre des screenshots de l'effet que mon incrustation produit. EDIT :
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); }
En tout cas merci d'avance à celui (ou celle) qui aura lu jusque là
Partager