00001 #ifdef USING_XVMC_OPENGL
00002
00003 #include "XvMCSurfaceTypes.h"
00004 #include "xvmctextures.h"
00005 #include "osd.h"
00006 #include "osdsurface.h"
00007 #include "frame.h"
00008
00009 #define LOC QString("XvMCTex: ")
00010 #define LOC_ERR QString("XvMCTex, Error: ")
00011
00012 static vector<GLuint> create_textures(
00013 Display *XJ_disp,
00014 GLXWindow glx_window, GLXContext glx_context,
00015 GLXPbuffer glx_pbuffer, const QSize &tex_size,
00016 uint num_of_textures);
00017
00018 XvMCTextures *XvMCTextures::Create(Display *XJ_disp, Window XJ_curwin,
00019 int XJ_screen_num,
00020 const QSize &video_dim,
00021 const QSize &window_size)
00022 {
00023 XvMCTextures *tmp = new XvMCTextures();
00024 if (tmp && tmp->Init(XJ_disp, XJ_curwin, XJ_screen_num,
00025 video_dim, window_size))
00026 {
00027 return tmp;
00028 }
00029
00030 if (tmp)
00031 delete tmp;
00032
00033 return NULL;
00034 }
00035
00036 bool XvMCTextures::Init(Display *disp, Window XJ_curwin,
00037 int XJ_screen_num,
00038 const QSize &video_dim,
00039 const QSize &window_size)
00040 {
00041 VERBOSE(VB_IMPORTANT, LOC + "Init");
00042
00043 if (!disp)
00044 {
00045 VERBOSE(VB_IMPORTANT, LOC_ERR + "Init() no display!");
00046 return false;
00047 }
00048
00049 XJ_disp = disp;
00050
00051 if (!init_opengl())
00052 {
00053 VERBOSE(VB_PLAYBACK, LOC_ERR + "Failed to initialize OpenGL support.");
00054
00055 return false;
00056 }
00057
00058 uint major = 0, minor = 0;
00059 if (!get_glx_version(XJ_disp, major, minor))
00060 {
00061 VERBOSE(VB_PLAYBACK, LOC_ERR + "GLX extension not present.");
00062
00063 return false;
00064 }
00065
00066 if ((1 == major) && (minor < 3))
00067 {
00068 VERBOSE(VB_PLAYBACK, LOC_ERR + QString(
00069 "Need GLX 1.3 or better, have %1.%2")
00070 .arg(major).arg(minor));
00071
00072 return false;
00073 }
00074
00075 if (!glx_fbconfig)
00076 {
00077 glx_fbconfig = get_fbuffer_cfg(
00078 XJ_disp, XJ_screen_num, get_attr_cfg(kRenderRGBA));
00079 }
00080
00081 if (glx_fbconfig)
00082 glx_pbuffer = get_pbuffer(XJ_disp, glx_fbconfig, video_dim);
00083
00084 if (!glx_context)
00085 X11S(glx_context = glXCreateNewContext(XJ_disp, glx_fbconfig,
00086 GLX_RGBA_TYPE, NULL, 1));
00087
00088 XVisualInfo *vis_info;
00089 vis_info = glXGetVisualFromFBConfig(XJ_disp, glx_fbconfig);
00090 gl_window = get_gl_window(XJ_disp, XJ_curwin, vis_info,
00091 window_size, true);
00092
00093 glx_window = get_glx_window(XJ_disp, glx_fbconfig, gl_window, glx_context,
00094 glx_pbuffer, window_size);
00095
00096 glXMakeContextCurrent(XJ_disp, glx_window, glx_pbuffer, glx_context);
00097 glCheck();
00098 glXMakeContextCurrent(XJ_disp, None, None, NULL);
00099
00100 gl_vid_textures = create_textures(
00101 XJ_disp, glx_window, glx_context, glx_pbuffer, video_dim, 1);
00102 gl_vid_tex_size.resize(gl_vid_textures.size());
00103
00104 gl_osd_textures = create_textures(
00105 XJ_disp, glx_window, glx_context, glx_pbuffer, video_dim, 1);
00106 gl_osd_tex_size.resize(gl_vid_textures.size());
00107
00108 XSync(XJ_disp, 0);
00109
00110 gl_display_size = window_size;
00111 gl_video_size = video_dim;
00112
00113 glXMakeContextCurrent(XJ_disp, glx_window, glx_pbuffer, glx_context);
00114 glCheck();
00115 glXMakeContextCurrent(XJ_disp, None, None, NULL);
00116
00117 VERBOSE(VB_IMPORTANT, LOC +
00118 QString("InitXvMCGL: video_size: %1x%2 vis_size: %3x%4")
00119 .arg(gl_video_size.width()).arg(gl_video_size.height())
00120 .arg(gl_display_size.width()).arg(gl_display_size.height()));
00121
00122 VERBOSE(VB_IMPORTANT, LOC <<endl
00123 <<"glx_fbconfig: "<<glx_fbconfig<<endl
00124 <<"gl_window: "<<gl_window<<endl
00125 <<"glx_window: "<<glx_window<<endl
00126 <<"gl_vid_tex: "<<gl_vid_textures[0]<<endl
00127 <<"gl_osd_tex: "<<gl_osd_textures[0]<<endl);
00128
00129 return true;
00130 }
00131
00132 void XvMCTextures::DeInit(void)
00133 {
00134 VERBOSE(VB_IMPORTANT, LOC + "DeInit");
00135 if (!XJ_disp)
00136 return;
00137
00138 X11L;
00139 glXMakeContextCurrent(XJ_disp, None, None, NULL);
00140 glXDestroyContext(XJ_disp, glx_context); glx_context = 0;
00141 glXDestroyWindow( XJ_disp, glx_window); glx_window = 0;
00142 glXDestroyPbuffer(XJ_disp, glx_pbuffer); glx_pbuffer = 0;
00143 XDestroyWindow( XJ_disp, gl_window); gl_window = 0;
00144 gl_vid_textures.clear();
00145 gl_osd_textures.clear();
00146 XJ_disp = NULL;
00147 X11U;
00148 }
00149
00150 bool XvMCTextures::ProcessOSD(OSD *osd)
00151 {
00152 OSDSurface *osdsurf = NULL;
00153
00154 if (osd)
00155 osdsurf = osd->Display();
00156
00157 if (!osdsurf || gl_osd_textures.empty() ||
00158 gl_osd_revision == osdsurf->GetRevision())
00159 {
00160 if (!osdsurf && gl_osd_visible)
00161 {
00162 gl_osd_visible = false;
00163 VERBOSE(VB_IMPORTANT, "OSD not visible");
00164 return true;
00165 }
00166 return false;
00167 }
00168
00169 uint bpl = gl_video_size.width() << 2;
00170 uint sz = bpl * gl_video_size.height();
00171 unsigned char *pixels = gl_osd_tmp_buf;
00172 if (sz > gl_osd_tmp_buf_size)
00173 {
00174 pixels = new unsigned char[sz + 256];
00175 if (gl_osd_tmp_buf)
00176 delete [] gl_osd_tmp_buf;
00177 gl_osd_tmp_buf = pixels;
00178 gl_osd_tmp_buf_size = sz;
00179 }
00180 bzero(pixels, sz * sizeof(unsigned char));
00181
00182 osdsurf->BlendToARGB(pixels, bpl, gl_video_size.height(),
00183 false, 0);
00184
00185 for (uint i = 0; i < sz; i += 4)
00186 {
00187 unsigned char tmp[4] =
00188 { pixels[i+0], pixels[i+1], pixels[i+2], pixels[i+3] };
00189
00190 pixels[i+0] = tmp[2];
00191
00192 pixels[i+2] = tmp[0];
00193 pixels[i+3] = tmp[3];
00194 }
00195
00196 X11L;
00197 GLuint rect_type = GL_TEXTURE_RECTANGLE_NV;
00198
00199 glXMakeContextCurrent(XJ_disp, glx_window, glx_pbuffer, glx_context);
00200
00201 glBindTexture(rect_type, gl_osd_textures[gl_osd_tex_index]);
00202 glTexParameterf(rect_type, GL_TEXTURE_WRAP_S, GL_CLAMP);
00203 glTexParameterf(rect_type, GL_TEXTURE_WRAP_T, GL_CLAMP);
00204 glTexParameterf(rect_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00205 glTexParameterf(rect_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00206
00207 glTexImage2D(rect_type, 0, GL_RGBA8,
00208 gl_video_size.width(), gl_video_size.height(),
00209 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
00210
00211 glXMakeContextCurrent(XJ_disp, None, None, NULL);
00212
00213 gl_osd_revision = osdsurf->GetRevision();
00214 gl_osd_tex_size[gl_osd_tex_index] = gl_video_size;
00215
00216 X11U;
00217
00218 if (!gl_osd_visible)
00219 VERBOSE(VB_IMPORTANT, "OSD visible");
00220
00221 gl_osd_visible = true;
00222
00223 return true;
00224 }
00225
00226 void XvMCTextures::PrepareFrame(XvMCSurface *surf,
00227 const QRect &video_rect, int scan)
00228 {
00229 int field = (scan <= 0) ? 1 : scan;
00230
00231 X11L;
00232
00233 glXMakeContextCurrent(XJ_disp, glx_window, glx_pbuffer, glx_context);
00234
00236
00237 int h = gl_video_size.height();
00238 if (XVMC_FRAME_PICTURE != field)
00239 h = gl_video_size.height() / 2;
00240
00241 uint tex_idx = gl_vid_tex_index;
00242
00243 glBindTexture(GL_TEXTURE_RECTANGLE_NV,
00244 gl_vid_textures[tex_idx]);
00245
00246 XvMCCopySurfaceToGLXPbuffer(XJ_disp, surf, glx_pbuffer, 0, 0,
00247 gl_video_size.width(), h,
00248 0, 0, GL_FRONT_LEFT, field);
00249
00250 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_NV, 0, 0, 0, 0, 0,
00251 gl_video_size.width(), h);
00252
00253 gl_vid_tex_size[tex_idx] = QSize(gl_video_size.width(), h);
00254
00256
00257 last_video_rect = video_rect;
00258
00260
00261 glFlush();
00262
00263 glXMakeContextCurrent(XJ_disp, None, None, NULL);
00264
00265 X11U;
00266 }
00267
00268 void XvMCTextures::CompositeFrameAndOSD(int scan)
00269 {
00270 if (last_video_rect.width() <= 0)
00271 return;
00272
00273 QRect video_rect = last_video_rect;
00274
00275 int field = (scan <= 0) ? 1 : scan;
00276
00277 float bob_delta = 0.0f;
00278 if (XVMC_FRAME_PICTURE != field)
00279 {
00280 bob_delta = -0.25f / gl_vid_tex_size[gl_vid_tex_index].height();
00281 if (XVMC_BOTTOM_FIELD == field)
00282 bob_delta = -bob_delta;
00283 }
00284
00285 float xobeg = video_rect.left();
00286 float xoend = video_rect.right();
00287 float yobeg = video_rect.top();
00288 float yoend = video_rect.bottom();
00289
00290 glClearColor (0.0, 0.0, 0.0, 0.5);
00291 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00292
00293 glEnable(GL_BLEND);
00294 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00295
00296 {
00297 float xbeg = 0.0f;
00298 float xend = gl_vid_tex_size[gl_vid_tex_index].width();
00299 float ybeg = bob_delta;
00300 float yend = bob_delta + gl_vid_tex_size[gl_vid_tex_index].height();
00301
00302 glBindTexture(GL_TEXTURE_RECTANGLE_NV,
00303 gl_vid_textures[gl_vid_tex_index]);
00304 glBegin(GL_QUADS);
00305 glTexCoord2f(xbeg, ybeg); glVertex3f(xobeg, yobeg, +0.0f);
00306 glTexCoord2f(xbeg, yend); glVertex3f(xobeg, yoend, +0.0f);
00307 glTexCoord2f(xend, yend); glVertex3f(xoend, yoend, +0.0f);
00308 glTexCoord2f(xend, ybeg); glVertex3f(xoend, yobeg, +0.0f);
00309 glEnd();
00310 }
00311
00312 if (gl_osd_visible)
00313 {
00314 float xbeg = 0.0f;
00315 float ybeg = 0.0f;
00316 float xend = gl_osd_tex_size[gl_osd_tex_index].width();
00317 float yend = gl_osd_tex_size[gl_osd_tex_index].height();
00318
00319 glBindTexture(GL_TEXTURE_RECTANGLE_NV,
00320 gl_osd_textures[gl_osd_tex_index]);
00321
00322 glBegin(GL_QUADS);
00323 glTexCoord2f(xend, ybeg); glVertex3f(xoend, yoend, -1.0f);
00324 glTexCoord2f(xend, yend); glVertex3f(xoend, yobeg, -1.0f);
00325 glTexCoord2f(xbeg, yend); glVertex3f(xobeg, yobeg, -1.0f);
00326 glTexCoord2f(xbeg, ybeg); glVertex3f(xobeg, yoend, -1.0f);
00327 glEnd();
00328 }
00329 }
00330
00331 void XvMCTextures::Show(int scan)
00332 {
00333 X11L;
00334
00335 glXMakeContextCurrent(XJ_disp, glx_window, glx_pbuffer, glx_context);
00336
00337 CompositeFrameAndOSD(scan);
00338
00339 glFinish();
00340 glXSwapBuffers(XJ_disp, glx_window);
00341
00342 glXMakeContextCurrent(XJ_disp, None, None, NULL);
00343
00344 X11U;
00345 }
00346
00347 static vector<GLuint> create_textures(
00348 Display *XJ_disp,
00349 GLXWindow glx_window, GLXContext glx_context,
00350 GLXPbuffer glx_pbuffer, const QSize &tex_size,
00351 uint num_of_textures)
00352 {
00353 GLuint rect_type = GL_TEXTURE_RECTANGLE_NV;
00354 vector<GLuint> tex;
00355 tex.resize(num_of_textures);
00356
00357 X11L;
00358
00359 glXMakeContextCurrent(XJ_disp, glx_window, glx_pbuffer, glx_context);
00360
00361 glGenTextures(num_of_textures, &tex[0]);
00362
00363
00364 for (uint i = 0; i < num_of_textures; i++)
00365 {
00366 glBindTexture(rect_type, tex[i]);
00367 glTexParameterf(rect_type, GL_TEXTURE_WRAP_S, GL_CLAMP);
00368 glTexParameterf(rect_type, GL_TEXTURE_WRAP_T, GL_CLAMP);
00369 glTexParameterf(rect_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00370 glTexParameterf(rect_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00371
00372 glTexImage2D(rect_type, 0, GL_RGB8,
00373 tex_size.width(), tex_size.height(),
00374 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
00375 }
00376
00377 glXMakeContextCurrent(XJ_disp, None, None, NULL);
00378
00379 X11U;
00380
00381 return tex;
00382 }
00383
00384 #endif // USING_XVMC_OPENGL