Mostly operational pixel shaded YV12->RGB32 conversion. (needs glew for now)

Originally committed to SVN as r899.
This commit is contained in:
Rodrigo Braz Monteiro 2007-01-27 06:15:25 +00:00
parent 9a292d6091
commit 3b9afa126e
10 changed files with 252 additions and 37 deletions

View file

@ -36,10 +36,18 @@
///////////
// Headers
#include <GL/glew.h>
#include <GL/gl.h>
#include "gl_wrap.h"
////////////////
// GLEW library
#if __VISUALC__ >= 1200
#pragma comment(lib,"glew32.lib")
#endif
/////////////
// Draw line
void OpenGLWrapper::DrawLine(float x1,float y1,float x2,float y2) {
@ -222,3 +230,153 @@ void OpenGLWrapper::SetModeFill() {
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
}
}
//////////////////////////
// Are shaders available?
bool OpenGLWrapper::ShadersAvailable() {
if (GLEW_VERSION_2_0) return true;
return false;
}
///////////////////
// Initialize GLEW
void OpenGLWrapper::InitializeGLEW() {
static bool initialized = false;
if (!initialized) {
initialized = true;
glewInit();
}
}
//////////////////////
// Set current shader
void OpenGLWrapper::SetShader(GLuint i) {
InitializeGLEW();
glUseProgram(i);
}
//////////////////////////
// Destroy shader program
void OpenGLWrapper::DestroyShaderProgram(GLuint i) {
InitializeGLEW();
SetShader(0);
glDeleteProgram(i);
}
////////////////////////////////////////////////////////
// Create shader program from vertex and pixel shaders
GLuint OpenGLWrapper::CreateShaderProgram(GLuint vertex,GLuint pixel) {
// Create instance
InitializeGLEW();
GLuint program = glCreateProgram();
// Attach shaders
glAttachShader(program,vertex);
glAttachShader(program,pixel);
// Link
glLinkProgram(program);
// Return
return program;
}
/////////////////////////////////
// Create standard Vertex shader
GLuint OpenGLWrapper::CreateStandardVertexShader() {
// Create instance
InitializeGLEW();
GLuint shader = glCreateShader(GL_VERTEX_SHADER);
// Read source
char source[] =
"void main() {\n"
" gl_TexCoord[0] = gl_MultiTexCoord0;\n"
" gl_Position = ftransform();\n"
"}";
const GLchar *src = source;
glShaderSource(shader,1,&src,NULL);
// Compile
glCompileShader(shader);
// Return
return shader;
}
///////////////////////////////////
// Create YV12->RGB32 Pixel Shader
GLuint OpenGLWrapper::CreateYV12PixelShader() {
// Create instance
InitializeGLEW();
GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
// Read source
char source[] =
"uniform sampler2D tex;\n"
"uniform vec2 off1;\n"
"uniform vec2 off2;\n"
"\n"
"void main() {\n"
" vec2 pos = gl_TexCoord[0].st;\n"
" vec4 y_bias = vec4(-0.063,-0.063,-0.063,0.0);\n"
" vec4 y_mult = vec4(1.164,1.164,1.164,1.0);\n"
" vec4 color_y = (texture2D(tex,pos) + y_bias) * y_mult;\n"
" pos *= 0.5;\n"
" vec4 uv_bias = vec4(-0.5,-0.5,-0.5,0.0);\n"
" vec4 uv_mult = vec4(0.0,-0.391,2.018,1.0);\n"
//" vec4 uv_mult = vec4(0.0,-0.344,1.770,1.0);\n"
" vec4 color_u = (texture2D(tex,pos + off1) + uv_bias) * uv_mult;\n"
" uv_mult = vec4(1.596,-0.813,0.0,1.0);\n"
//" uv_mult = vec4(1.403,-0.714,0.0,1.0);\n"
" vec4 color_v = (texture2D(tex,pos + off2) + uv_bias) * uv_mult;\n"
" gl_FragColor = color_y + color_u + color_v;\n"
"}";
const GLchar *src = source;
glShaderSource(shader,1,&src,NULL);
// Compile
glCompileShader(shader);
// Return
return shader;
}
/////////////////////////////////////
// Create YV12->RGB32 Shader Program
GLuint OpenGLWrapper::CreateYV12Shader(float tw,float th) {
// Create vertex shader
GLuint ver = OpenGLWrapper::CreateStandardVertexShader();
if (glGetError() != 0) throw _T("Error creating generic vertex shader");
// Create pixel shader
GLuint pix = OpenGLWrapper::CreateYV12PixelShader();
if (glGetError() != 0) throw _T("Error creating YV12 pixel shader");
// Create program
GLuint program = OpenGLWrapper::CreateShaderProgram(ver,pix);
if (glGetError() != 0) throw _T("Error creating shader program");
// Set shader
OpenGLWrapper::SetShader(program);
if (glGetError() != 0) throw _T("Error setting shader");
// Set uniform variables
GLuint address = glGetUniformLocation(program,"tex");
glUniform1i(address, 0);
address = glGetUniformLocation(program,"off1");
glUniform2f(address, 0.0f, th);
address = glGetUniformLocation(program,"off2");
glUniform2f(address, tw*0.5f, th);
// Return shader
return program;
}

View file

@ -45,6 +45,11 @@ private:
float r2,g2,b2,a2;
int lw;
static void InitializeGLEW();
static GLuint CreateStandardVertexShader();
static GLuint CreateYV12PixelShader();
static GLuint CreateShaderProgram(GLuint vertex,GLuint pixel);
public:
void SetLineColour(wxColour col,float alpha=1.0f,int width=1);
void SetFillColour(wxColour col,float alpha=1.0f);
@ -55,4 +60,9 @@ public:
void DrawCircle(float x,float y,float radius) { DrawEllipse(x,y,radius,radius); }
void DrawRectangle(float x1,float y1,float x2,float y2);
void DrawRing(float x,float y,float r1,float r2,float ar=1.0f,float arcStart=0.0f,float arcEnd=0.0f);
static bool ShadersAvailable();
static void SetShader(GLuint i);
static void DestroyShaderProgram(GLuint i);
static GLuint CreateYV12Shader(float tw,float th);
};

View file

@ -148,6 +148,7 @@ void OptionsManager::LoadDefaults() {
SetBool(_T("Allow Ancient Avisynth"),false);
SetText(_T("Video Provider"),_T("Avisynth"));
SetText(_T("Subtitles Provider"),_T("CSRI"));
SetBool(_T("Video Use Pixel Shaders"),false);
// Audio Options
SetBool(_T("Audio Next Line on Commit"),true);

View file

@ -78,6 +78,9 @@
#include <wx/event.h>
#include <wx/wxscintilla.h>
#include <wx/string.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <wx/glcanvas.h>

View file

@ -65,6 +65,7 @@
#include "video_slider.h"
#include "video_box.h"
#include "utils.h"
#include "gl_wrap.h"
///////
@ -93,6 +94,7 @@ VideoContext::VideoContext() {
glContext = NULL;
lastTex = 0;
lastFrame = -1;
yv12shader = 0;
// Set options
audio = NULL;
@ -142,6 +144,12 @@ void VideoContext::Clear() {
/////////
// Reset
void VideoContext::Reset() {
// Reset shader
if (yv12shader) {
OpenGLWrapper::DestroyShaderProgram(yv12shader);
yv12shader = 0;
}
// Clear keyframes
KeyFrames.Clear();
keyFramesLoaded = false;
@ -426,6 +434,7 @@ GLuint VideoContext::GetFrameAsTexture(int n) {
glShadeModel(GL_FLAT);
// Generate texture with GL
//glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &lastTex);
if (glGetError() != 0) throw _T("Error generating texture.");
glBindTexture(GL_TEXTURE_2D, lastTex);
@ -439,9 +448,9 @@ GLuint VideoContext::GetFrameAsTexture(int n) {
// Load image data into texture
int height = frame.h;
if (frame.format == FORMAT_YV12) height = frame.h * 3 / 2;
if (frame.format == FORMAT_YV12) height = height * 3 / 2;
int tw = SmallestPowerOf2(frame.w);
int th = SmallestPowerOf2(frame.h);
int th = SmallestPowerOf2(height);
texW = float(frame.w)/float(tw);
texH = float(frame.h)/float(th);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,tw,th,0,format,GL_UNSIGNED_BYTE,NULL);
@ -454,6 +463,11 @@ GLuint VideoContext::GetFrameAsTexture(int n) {
// Set priority
float priority = 1.0f;
glPrioritizeTextures(1,&lastTex,&priority);
// Create shader if necessary
if (frame.format == FORMAT_YV12 && yv12shader == 0) {
yv12shader = OpenGLWrapper::CreateYV12Shader(texW,texH);
}
}
// Load texture data
@ -730,3 +744,10 @@ void VideoContext::SetAspectRatio(int _type, double value) {
arValue = value;
UpdateDisplays(true);
}
////////////////////////////
// Enable or disable shader
void VideoContext::SetShader(bool enabled) {
OpenGLWrapper::SetShader(enabled ? yv12shader : 0);
}

View file

@ -67,6 +67,7 @@ private:
std::list<VideoDisplay*> displayList;
GLuint lastTex;
GLuint yv12shader;
int lastFrame;
wxGLContext *glContext;
VideoFrameFormat vidFormat;
@ -130,6 +131,7 @@ public:
float GetTexW() { return texW; }
float GetTexH() { return texH; }
VideoFrameFormat GetFormat() { return vidFormat; }
void SetShader(bool enabled);
bool IsLoaded() { return loaded; }
bool IsPlaying() { return isPlaying; }

View file

@ -203,8 +203,9 @@ void VideoDisplay::Render() {
float left = 0.0;
float right = context->GetTexW();
// Draw interleaved frame or luma of YV12
// Draw frame
glDisable(GL_BLEND);
context->SetShader(true);
glBindTexture(GL_TEXTURE_2D, VideoContext::Get()->GetFrameAsTexture(-1));
glColor4f(1.0f,1.0f,1.0f,1.0f);
glBegin(GL_QUADS);
@ -221,11 +222,7 @@ void VideoDisplay::Render() {
glTexCoord2f(right,top);
glVertex2f(sw,0);
glEnd();
// Draw UV planes
if (context->GetFormat() == FORMAT_YV12) {
}
context->SetShader(false);
// Draw overlay
visual->DrawOverlay();

View file

@ -188,6 +188,16 @@ void VideoDisplayVisual::DrawOverlay() {
}
else GetLineScale(diag,scalX,scalY);
// Get angle
GetLineRotation(diag,rx,ry,rz);
if (isCur) {
if (mode == 2) rz = curAngle;
else if (mode == 3) {
rx = curAngle;
ry = curAngle2;
}
}
// Mouse over?
if (diag == diagHigh) {
high = true;
@ -225,16 +235,6 @@ void VideoDisplayVisual::DrawOverlay() {
DrawLine(dx,dy-16,dx,dy+16);
DrawLine(dx-16,dy,dx+16,dy);
// Get angle
GetLineRotation(diag,rx,ry,rz);
if (isCur) {
if (mode == 2) rz = curAngle;
else {
rx = curAngle;
ry = curAngle2;
}
}
// Rotate Z
if (mode == 2) {
// Transform
@ -387,37 +387,54 @@ void VideoDisplayVisual::DrawOverlay() {
// Scale
if (mode == 4) {
// Scale parameters
// Set dx/dy
int len = 160;
int lenx = int(1.6 * scalX);
int leny = int(1.6 * scalY);
dx = MID(len/2+10,dx,sw-len/2-30);
dy = MID(len/2+10,dy,sh-len/2-30);
int drawX = dx + len/2 + 10;
int drawY = dy + len/2 + 10;
// Transform grid
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glTranslatef(dx,dy,0.0f);
float matrix[16] = { 2500, 0, 0, 0, 0, 2500, 0, 0, 0, 0, 1, 1, 0, 0, 2500, 2500 };
glMultMatrixf(matrix);
glScalef(1.0f,1.0f,8.0f);
if (ry != 0.0f) glRotatef(ry,0.0f,-1.0f,0.0f);
if (rx != 0.0f) glRotatef(rx,-1.0f,0.0f,0.0f);
if (rz != 0.0f) glRotatef(rz,0.0f,0.0f,-1.0f);
// Scale parameters
int lenx = int(1.6 * scalX);
int leny = int(1.6 * scalY);
int drawX = len/2 + 10;
int drawY = len/2 + 10;
// Draw length markers
SetLineColour(colour[3],1.0f,2);
DrawLine(dx-lenx/2,drawY+10,dx+lenx/2,drawY+10);
DrawLine(drawX+10,dy-leny/2,drawX+10,dy+leny/2);
DrawLine(-lenx/2,drawY+10,lenx/2,drawY+10);
DrawLine(drawX+10,-leny/2,drawX+10,leny/2);
SetLineColour(colour[0],1.0f,1);
SetFillColour(colour[brushCol],0.3f);
DrawCircle(dx+lenx/2,drawY+10,4);
DrawCircle(drawX+10,dy-leny/2,4);
DrawCircle(lenx/2,drawY+10,4);
DrawCircle(drawX+10,-leny/2,4);
// Draw horizontal scale
SetLineColour(colour[0],1.0f,1);
DrawRectangle(dx-len/2,drawY,dx+len/2+1,drawY+5);
DrawRectangle(-len/2,drawY,len/2+1,drawY+5);
SetLineColour(colour[0],1.0f,2);
DrawLine(dx-len/2+1,drawY+5,dx-len/2+1,drawY+15);
DrawLine(dx+len/2,drawY+5,dx+len/2,drawY+15);
DrawLine(-len/2+1,drawY+5,-len/2+1,drawY+15);
DrawLine(len/2,drawY+5,len/2,drawY+15);
// Draw vertical scale
SetLineColour(colour[0],1.0f,1);
DrawRectangle(drawX,dy-len/2,drawX+5,dy+len/2+1);
DrawRectangle(drawX,-len/2,drawX+5,len/2+1);
SetLineColour(colour[0],1.0f,2);
DrawLine(drawX+5,dy-len/2+1,drawX+15,dy-len/2+1);
DrawLine(drawX+5,dy+len/2,drawX+15,dy+len/2);
DrawLine(drawX+5,-len/2+1,drawX+15,-len/2+1);
DrawLine(drawX+5,len/2,drawX+15,len/2);
// Restore gl's state
glPopMatrix();
}
// Clip

View file

@ -49,6 +49,7 @@
#include "main.h"
#include "vfr.h"
#include "ass_file.h"
#include "gl_wrap.h"
////////////
@ -293,8 +294,10 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priori
}
// Convert to RGB32
if (OpenGLWrapper::ShadersAvailable() && !Options.AsBool(_T("Video Use Pixel Shaders"))) {
script = env->Invoke("ConvertToRGB32", script);
AVSTRACE(_T("AvisynthVideoProvider::OpenVideo: Converted to RGB32"));
}
// Directshow
//if (usedDirectshow) wxMessageBox(_T("Warning! The file is being opened using Avisynth's DirectShowSource, which has unreliable seeking. Frame numbers might not match the real number. PROCEED AT YOUR OWN RISK!"),_T("DirectShowSource warning"),wxICON_EXCLAMATION);

View file

@ -52,6 +52,8 @@
#include "utils.h"
#include "vfr.h"
#include "videosink.h"
#include "gl_wrap.h"
#include "options.h"
///////////////////////
@ -292,8 +294,9 @@ HRESULT DirectShowVideoProvider::OpenVideo(wxString _filename) {
if (!sink2) return E_NOINTERFACE;
// Set allowed types for sink
//sink->SetAllowedTypes(IVS_RGB32|IVS_YV12|IVS_YUY2);
sink->SetAllowedTypes(IVS_RGB24);
unsigned int types = IVS_RGB24 | IVS_RGB32;
if (OpenGLWrapper::ShadersAvailable() && !Options.AsBool(_T("Video Use Pixel Shaders"))) types = types | IVS_YV12;
sink->SetAllowedTypes(types);
// Pass the event to sink, so it gets set when a frame is available
ResetEvent(m_hFrameReady);