ich bastel gerade einen YUV -> RGB GLSL Fragment Shader und erziele fortschritte. Genauer gesagt scheint habe ich es endlich geschaft ein RGB bild aus den YUV daten zu generieren, aber leider ist die Auflösung zu niedrig.
Es wirkt sehr pixelig. Hier sind screenshots wie es aussehen soll und wie es mit dem Shader aussieht:
Original RGB24:
GLSL YUY2 Shader:
Ich habe keine idee warum das so pixelig rauskommt, evtl. ist irgendwo ein Fehler seh ihn aber nicht ?
Vielleicht helfen die folgende Hinweise:
- Die YUV Daten sind in einer 320x480 RGBA GL Texture gespeichert und im format GL_RGBA, GL_BGRA angegeben. - Gezeichnet wird ein Quad in der aktuellen Auflösung des Clientrects (Fenster) mit den Texture Koordinaten 0-0, 640-480. - Projection ist natürlich ortho. - Bevor der Shader aktiviert wird, wird die texture ganz normal gebunden - Die texture ist als GL_TEXTURE_RECTANGLE target gebunden. Defakto nutze ich auch sampler2DRect als uniform variable für meine texture.
// Fische die y-u-y-v daten aus den RGBA farben float y1 = texture2DRect(yuvTexture, vec2(nx, ny)).r; float u = texture2DRect(yuvTexture, vec2(nx, ny)).g; float y2 = texture2DRect(yuvTexture, vec2(nx, ny)).b; float v = texture2DRect(yuvTexture, vec2(nx, ny)).a;
// Jeder erste pixel wird mit y1 ausgeben // Jeder zweite pixel wird mit y2 ausgeben // Funktioniert nicht! vec4 rgb; if (mod(gl_FragCoord.x, 2.0) == 0) { rgb = YUVToRGBA(y1, u, v); } else { rgb = YUVToRGBA(y2, u, v); } gl_FragColor = rgb;
// Berechne RGBA aus yuv wert gl_FragColor = YUVToRGBA(yanteil, u, v); */ }
Ich bekomme mit 4 byte (RGBA) 2 Pixel als endergebnis, kann aber nur 1 Pixel ausgeben. Möglicherweise steckt hier der Wurm, aber ich habe keine idee, wie ich den 2 pixel auch mit ausgeben kann.
Das modulo fragcoord 2 funktioniert nicht, Tip hatte ich von Aya. Das habe ich getestet, indem ich die resultierende farbe im If und else block verändert habe. Defakto wird immer Else ausgegeben.
Bitte um Hilfe.
Wenn es hilft poste ich auch gern den kompletten Lazarus Source.
// Fische die y-u-y-v daten aus den RGBA farben float y1 = texture2DRect(yuvTexture, vec2(nx, ny)).r; float u = texture2DRect(yuvTexture, vec2(nx, ny)).g; float y2 = texture2DRect(yuvTexture, vec2(nx, ny)).b; float v = texture2DRect(yuvTexture, vec2(nx, ny)).a;
Nicht verantwortlich für dein Problem.....aber Performance-Technisch.....du machst hier 4 mal die gleiche Texturanfrage. Zwar gibt es einen Cache, trotzdem ist das recht lahm. Besser so:
// Fische die y-u-y-v daten aus den RGBA farben float y1 = texture2DRect(yuvTexture, vec2(nx, ny)).r; float u = texture2DRect(yuvTexture, vec2(nx, ny)).g; float y2 = texture2DRect(yuvTexture, vec2(nx, ny)).b; float v = texture2DRect(yuvTexture, vec2(nx, ny)).a;
Nicht verantwortlich für dein Problem.....aber Performance-Technisch.....du machst hier 4 mal die gleiche Texturanfrage. Zwar gibt es einen Cache, trotzdem ist das recht lahm. Besser so:
// Fische die y-u-y-v daten aus den RGBA farben vec4 texel = texture2DRect(yuvTexture, vec2(nx, ny)); float y1 = texel.r; float u = texel.g; float y2 = texel.b; float v = texel.a;
int x = int(gl_FragCoord.x);
// Jeder erste pixel wird mit y1 ausgeben // Jeder zweite pixel wird mit y2 ausgeben vec4 rgb; if (mod(x, 2) == 0) { rgb = YUVToRGBA(y2, u, v); } else { rgb = YUVToRGBA(y1, u, v); } gl_FragColor = rgb;
Ich hab mal ein C Beispiel einer GLSL YUV-RGB Konvertierung gefunden. Dies nutzt aber 3 Luminance Texturen und nicht 1 RGBA wie ich.
Evtl. könnte das helfen. Die schreiben im Kommentar das es einfach sei, das für eine Single texture zum laufen zu kriegen. Nur find ich das definitiv nicht einfach.
Habe auch nochmal den Speicher überprüft. Die 320 x 480 als RGBA Texture ist exakt so gross wie die YUV quell daten. Somit passen zumindest die daten. Das kann man also ausschliesen.
Hier mein testprogramm als Binary mit Shader und Sampledateien:
Mit leertaste kann man die Sample formate durchschalten. Durch das umschalten, wird die aktuelle Texture zerstört und durch eine neue ersetzt. Der Inhalt wird direkt aus der jeweiligen Sample datei gelesen.
Mit F kann man den Texturefilter von Nearest (Off) auf Linear (Bilinear) umstellen.
Der Shader ist nur für Sample YUY2 definiert, kann also nur damit genutzt werden. Der Shader source liegt im glsl ordner. Verwendet wird nur "yuv.frag".
Aufbau der sample datei (Nur zur info):
- VideoInfoHeader - Directshow Subtype (TGUID) z.b. MEDIASUBTYPE_RGB24. - Daten länge (Integer) - Der rest sind die YUV daten.
Registriert: Sa Aug 18, 2007 18:47 Beiträge: 694 Wohnort: Köln
Programmiersprache: Java
hi Finalspace,
ändere doch mal die Texturkoordinaten auf 320, 480 in der Anwendung. Also ohne die Division im Shader. Btw: Müsste man nicht auch 0,480 und 320,0 angeben können? Dadurch sollte doch die Textur direkt gespiegelt sein. TextureDimH bräuchtest du dann auch nicht mehr.
ändere doch mal die Texturkoordinaten auf 320, 480 in der Anwendung. Also ohne die Division im Shader. Btw: Müsste man nicht auch 0,480 und 320,0 angeben können? Dadurch sollte doch die Textur direkt gespiegelt sein. TextureDimH bräuchtest du dann auch nicht mehr.
Habe ich probiert, die Texture ist dann nur noch in der hälfte sichtbar und sieht echt merkwürdig aus. Das mit dem Spiegeln könnte man machen, aber ich mach das lieber im Fragment Shader, die eine Integer Operation reist es denk ich nicht raus oder ?
damadmax hat geschrieben:
Ausserdem wirft er bei mir folgende Warnings aus:
Dateianhang:
finalspace_glrenderer_warnings.jpg
Komisch, auf meinem notebook ATI X1400 mit 128 MB habe ich keine Warnings Ich zeige nämlich nur die Messagebox an, wenn ein error,failed oder warn string vorhanden ist.
Was auch richtig merkwürdig ist, das wenn ich die #version 140 ganz oben definiere, dann geht der shader gar nicht mehr (Version wird nicht unterstützt).
Ansich tut aber der Shader, weil vor allem texture rects ja gehen O_o
Ich probier das auf meinem standrechner mal aus. NV 8800 GT.
damadmax hat geschrieben:
EDIT: Ich glaub ich habs: Du darfst nicht den Modulo von FragCoord.x nehmen...du musst die Texturkoordinate nehmen.
Probiert, gleiches ergebnis. Ich hab nx und direkt die texture korrdinate probiert
Jop die texcoords sind für alle formate gleich. Jediglich ist die Texturegrösse in der Breite bei YUY2 der Hälfte reduziert.
Aber genau diesen effekt meine ich, diesen interlace effekt. Diesen bekomm ich einfach nicht weg
Auch mit änderung des modulos Im gegenteil, der if part wird nie verwendet. Kannst ja schnell so prüfen:
Code:
// Jeder erste pixel wird mit y1 ausgeben // Jeder zweite pixel wird mit y2 ausgeben vec4 rgb; if (mod(nx, 2.0) == 0.0) { rgb = vec4(1.0,0.0,0.0,0.0); //rgb = YUVToRGBA(y2, u, v); } else { rgb = YUVToRGBA(y1, u, v); } gl_FragColor = rgb;
Ach es ist zum mäuse melken.
Das ist bestimmt irgendwas triviales.
Achja, bekomme nun auch die Warnings bei der 8800 GT.
int x = int(nx) ; // Jeder erste pixel wird mit y1 ausgeben // Jeder zweite pixel wird mit y2 ausgeben vec4 rgb; if (mod(x, 2) == 0) { rgb = YUVToRGBA(y2, u, v); } else { rgb = YUVToRGBA(y1, u, v); }
Also 1/4 Texel in jede Richtung. Sieht auf jeden fall schonmal besser aus.
Wobei ich aber immer noch das beste Ergebnis mit dem von dir auskommentierten Teil gemacht hab:
Code:
float yanteil = (y1 + y2) * 0.5;
_________________ Es werde Licht. glEnable(GL_LIGHTING); Und es ward Licht.
Zitat aus einem Java Buch: "C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off"
Registriert: Do Jun 28, 2007 17:58 Beiträge: 193
Programmiersprache: Pascal, C
Das Problem ist allgemein, dass die YUYV oder YUV422-Daten für einen Pixel Werte für zwei RGB-Pixel beinhalten. Der Interpolator in texture2DRect weiß das jedoch nicht, und schmeißt die Pixelwerte natürlich durcheinander: Einzige Möglichkeit: Selbst richtig interpolieren.
Nach ein bisschen Überlegen bin ich auf folgenden Code gekommem: Das Ergebnis ist IMHO auf jeden Fall schon mal besser als das von deinem Code aus dem Beispielprogramm und sollte in die "richtige Richtung" weisen. Für mehr hatte ich jetzt auf die Schnelle keine Zeit:
Störend sind hier die Übergänge von fract(nx) von 0.999 nach 0.0.
Gibst du mal mittels
Code:
gl_FragColor = vec4(fract(nx), 0.0, 0.0, 0.0);
die Verteilung von "pos" aus und vergrößerst/verkleinerst das Fenster, so siehst du, dass der von dir eingestellte Texturfilter momentan auch noch einiges kaputtmacht. Auch solltest du mal die einzelnen Y/U/V Werte einzeln als RGB ausgeben, dann siehst du direkt, welcher der Werte die "Pixeligkeit" verursacht.
Allgemein ist mir aufgefallen: Shadercode der Integer oder "If" braucht, benutzt oftmals den falschen Ansatz. Es gibt weder feste Pixel noch sollten Sprünge in Betracht gezogen werden, da letztere den Shadercode sehr verlangsamen und in diesem Fall "feste" Pixel vorraussetzen.
Gibt es denn eine möglichkeit wie ich einen Fragment Shader debuggen kann ?
Also z.b. das ich weiss welche texcoords über den fragment shader reinkommen, wie die YUV daten aussehen. Alles damit ich überprüfen kann, was schief läuft.
Gibt es einen weg, wie ich daten irgendwie ausgeben kann ?
Weil es wohl doch nicht so einfach ist, diese YUV-RGB Konvertierung zu machen.
Ich denke ich werd vorerst wohl mit meiner Software Lösung leben müssen, die ja gut funktioniert, aber denk ich bei HD Videos wieder einbricht
Das projekt lade ich die nächsten tage sofern ich zeit finde mal inkl. source hoch. Aktuell ist meine Zeit leider begrenzt, ich muss das Kinderzimmer noch fertigmachen
Gibt es denn eine möglichkeit wie ich einen Fragment Shader debuggen kann ?
Naja, du die Ausgabe des Fragmentshaders (Farbe) zum debuggen benutzen. Für Texturkoordinaten und Normalen reicht das völlig. Es ist natürlich hilfreich wenn du den Shader möglichst bequem neu laden kannst....z.B. ein Tastendruck und sämtliche Shader werden neu geladen ohne das du dein Programm neustarten musst.
Gibt es denn eine möglichkeit wie ich einen Fragment Shader debuggen kann ?
Naja, du die Ausgabe des Fragmentshaders (Farbe) zum debuggen benutzen. Für Texturkoordinaten und Normalen reicht das völlig. Es ist natürlich hilfreich wenn du den Shader möglichst bequem neu laden kannst....z.B. ein Tastendruck und sämtliche Shader werden neu geladen ohne das du dein Programm neustarten musst.
Lustig genau das habe ich vorhin eingebaut
Mit G kann man die GLSL implementierung ein / ausschalten Mit R kann man das sample inkl. Shader neu laden
Es gibt nun auch ein debug fenster inder man allerart von infos sehen kann.
Yay es funktioniert und sieht 1 zu 1 so aus wie meine Software Dekodierung.
Das problem war die ganze Zeit das ich 2 Pixel per Fragment zeichnen wollte und somit immer 1 pixel verloren ging mehr oder weniger. Dafür hatte hat ich immer Y1, U, Y2 und V (RGBA) gehabt. Das hat dazu geführt, das man einen unschönen scanline effekt hatte.
Habe ein bischen im Internet Recherchiert, weil ich es doch irgendwie möglich sein muss, das ich mit OpenGL beim Texture hochladen, die Daten anderst anordnern kann, so das ich nur noch ein Y wert habe.
Bin Fündig geworden und habe folgende Zeilen gefunden die mich gerettet haben:
Code:
glTexImage2D(GL_TEXTURE_RECTANGLE,0,GL_RGBA8, W div 2, H, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, UVtex);
Nachdem ich das eingebaut habe, habe ich mit den Shader rumexperimentiert und habe erstmal nur die zweite (Y) Texture versucht auf den Bildschirm zu bringen. Klappte wunderbar, rot musste ich einfach ausgeben, das war mein Y wert.
UV hatte ein weilchen gedauert bis ich herausgefunden habe was für auswirkung das GL_UNSIGNED_INT_8_8_8_8_REV tut.
Verstehen tu ich aber immernoch nicht was genau bei GL_UNSIGNED_INT_8_8_8_8_REV im Speicher passiert. Dreht das einfach nur die Daten um ? Also von RGBA nach ABGR ? Wäre super wenn mir das jemand mal erklären könnte.
LUMINANCE_ALPHA ist klar, das sind 8 byte ingesamt (Luminance+Alpha) und somit werden immer nur 2er blöcke verwendet (R und A), wobei A nicht verwendet wird.
Andere frage:
Gibt es denn eine möglichkeit wie ich auf eine Farbe (Vec4) per Array drauf zugreifen kann ? Also was ich meine das ich nicht angeben "mycolor.r" sondern "mycolor[0]" ? Weil dann bräuchte ich nur einen Shader machen der für viele andere YUV formate auch funktioniert. Das würde dann mittels offset funktionieren oder ?
Mitglieder in diesem Forum: 0 Mitglieder und 12 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.