|
MythTV
0.26-pre
|
00001 // MythTV headers 00002 #include "mythcontext.h" 00003 #include "tv.h" 00004 #include "openglvideo.h" 00005 #include "myth_imgconvert.h" 00006 #include "mythrender_opengl.h" 00007 00008 // AVLib header 00009 extern "C" { 00010 #include "libavcodec/avcodec.h" 00011 } 00012 00013 #define LOC QString("GLVid: ") 00014 #define COLOUR_UNIFORM "m_colourMatrix" 00015 00016 class OpenGLFilter 00017 { 00018 public: 00019 vector<GLuint> fragmentPrograms; 00020 uint numInputs; 00021 vector<GLuint> frameBuffers; 00022 vector<GLuint> frameBufferTextures; 00023 DisplayBuffer outputBuffer; 00024 }; 00025 00065 OpenGLVideo::OpenGLVideo() : 00066 gl_context(NULL), video_disp_dim(0,0), 00067 video_dim(0,0), viewportSize(0,0), 00068 masterViewportSize(0,0), display_visible_rect(0,0,0,0), 00069 display_video_rect(0,0,0,0), video_rect(0,0,0,0), 00070 frameBufferRect(0,0,0,0), softwareDeinterlacer(QString::null), 00071 hardwareDeinterlacer(QString::null), hardwareDeinterlacing(false), 00072 colourSpace(NULL), viewportControl(false), 00073 inputTextureSize(0,0), currentFrameNum(0), 00074 inputUpdated(false), refsNeeded(0), 00075 textureRects(false), textureType(GL_TEXTURE_2D), 00076 helperTexture(0), defaultUpsize(kGLFilterResize), 00077 gl_features(0), videoTextureType(GL_BGRA), 00078 preferYCBCR(false) 00079 { 00080 } 00081 00082 OpenGLVideo::~OpenGLVideo() 00083 { 00084 OpenGLLocker ctx_lock(gl_context); 00085 Teardown(); 00086 } 00087 00088 void OpenGLVideo::Teardown(void) 00089 { 00090 if (helperTexture) 00091 gl_context->DeleteTexture(helperTexture); 00092 helperTexture = 0; 00093 00094 DeleteTextures(&inputTextures); 00095 DeleteTextures(&referenceTextures); 00096 00097 while (!filters.empty()) 00098 { 00099 RemoveFilter(filters.begin()->first); 00100 filters.erase(filters.begin()); 00101 } 00102 } 00103 00126 bool OpenGLVideo::Init(MythRenderOpenGL *glcontext, VideoColourSpace *colourspace, 00127 QSize videoDim, QSize videoDispDim, 00128 QRect displayVisibleRect, 00129 QRect displayVideoRect, QRect videoRect, 00130 bool viewport_control, QString options, 00131 bool hw_accel) 00132 { 00133 if (!glcontext) 00134 return false; 00135 00136 gl_context = glcontext; 00137 OpenGLLocker ctx_lock(gl_context); 00138 00139 video_dim = videoDim; 00140 video_disp_dim = videoDispDim; 00141 display_visible_rect = displayVisibleRect; 00142 display_video_rect = displayVideoRect; 00143 video_rect = videoRect; 00144 masterViewportSize = QSize(1920, 1080); 00145 frameBufferRect = QRect(QPoint(0,0), video_disp_dim); 00146 softwareDeinterlacer = ""; 00147 hardwareDeinterlacing = false; 00148 colourSpace = colourspace; 00149 viewportControl = viewport_control; 00150 inputTextureSize = QSize(0,0); 00151 currentFrameNum = -1; 00152 inputUpdated = false; 00153 00154 // OpenGL-Lite - use implementation specific extensions for updating frames 00155 if (options.contains("preferycbcr")) 00156 preferYCBCR = true; 00157 00158 // Set OpenGL feature support 00159 gl_features = gl_context->GetFeatures(); 00160 00161 if (viewportControl) 00162 gl_context->SetFence(); 00163 00164 SetViewPort(display_visible_rect.size()); 00165 00166 bool shaders = (gl_features & kGLExtFragProg) || (gl_features & kGLSL); 00167 bool fbos = gl_features & kGLExtFBufObj; 00168 bool uyvy = !getenv("OPENGL_NOUYVY"); 00169 bool ycbcr = (gl_features & kGLMesaYCbCr) || (gl_features & kGLAppleYCbCr); 00170 00171 // warn about the lite profile when it offers no benefit 00172 if (!ycbcr && preferYCBCR) 00173 { 00174 LOG(VB_GENERAL, LOG_WARNING, LOC + 00175 "You have selected the opengl-lite profile but no required OpenGL " 00176 "extensions are available."); 00177 } 00178 00179 // decide on best video input texture format 00180 videoTextureType = GL_BGRA; 00181 if (hw_accel) 00182 videoTextureType = GL_RGBA; 00183 else if ((shaders && fbos && uyvy) && !(ycbcr && preferYCBCR)) 00184 videoTextureType = MYTHTV_UYVY; 00185 else if ((!shaders || preferYCBCR) && (gl_features & kGLMesaYCbCr)) 00186 videoTextureType = GL_YCBCR_MESA; 00187 else if ((!shaders || preferYCBCR) && (gl_features & kGLAppleYCbCr)) 00188 videoTextureType = GL_YCBCR_422_APPLE; 00189 00190 // colourspace adjustments require shaders to operate on YUV textures 00191 if ((GL_BGRA != videoTextureType) && (MYTHTV_UYVY != videoTextureType)) 00192 colourSpace->SetSupportedAttributes(kPictureAttributeSupported_None); 00193 00194 // turn on bicubic filtering 00195 if (options.contains("openglbicubic")) 00196 { 00197 if (shaders && fbos) 00198 defaultUpsize = kGLFilterBicubic; 00199 else 00200 LOG(VB_PLAYBACK, LOG_ERR, LOC + 00201 "No OpenGL feature support for Bicubic filter."); 00202 } 00203 00204 // decide on best input texture type 00205 if ((GL_RGBA != videoTextureType) && (defaultUpsize != kGLFilterBicubic) && 00206 (gl_features & kGLExtRect)) 00207 { 00208 textureType = gl_context->GetTextureType(textureRects); 00209 } 00210 00211 // Create initial input texture and associated filter stage 00212 GLuint tex = CreateVideoTexture(video_dim, inputTextureSize); 00213 bool ok = false; 00214 00215 if ((GL_BGRA == videoTextureType) || (MYTHTV_UYVY == videoTextureType)) 00216 ok = tex && AddFilter(kGLFilterYUV2RGB); 00217 else 00218 ok = tex && AddFilter(kGLFilterResize); 00219 00220 if (ok) 00221 { 00222 if (GL_RGBA == videoTextureType) 00223 LOG(VB_GENERAL, LOG_INFO, LOC + "Using raw RGBA input textures."); 00224 else if ((GL_YCBCR_MESA == videoTextureType) || 00225 (GL_YCBCR_422_APPLE == videoTextureType)) 00226 LOG(VB_GENERAL, LOG_INFO, LOC + 00227 "Using YCbCr->BGRA input textures."); 00228 else if (MYTHTV_UYVY == videoTextureType) 00229 LOG(VB_GENERAL, LOG_INFO, LOC + 00230 "Using custom UYVY input textures."); 00231 else 00232 LOG(VB_GENERAL, LOG_INFO, LOC + 00233 "Using plain BGRA input textures."); 00234 inputTextures.push_back(tex); 00235 } 00236 else 00237 Teardown(); 00238 00239 if (filters.empty()) 00240 { 00241 LOG(VB_PLAYBACK, LOG_INFO, LOC + 00242 "Failed to setup colourspace conversion.\n\t\t\t" 00243 "Falling back to software conversion.\n\t\t\t" 00244 "Any opengl filters will also be disabled."); 00245 00246 videoTextureType = GL_BGRA; 00247 GLuint bgra32tex = CreateVideoTexture(video_dim, inputTextureSize); 00248 00249 if (bgra32tex && AddFilter(kGLFilterResize)) 00250 { 00251 inputTextures.push_back(bgra32tex); 00252 colourSpace->SetSupportedAttributes(kPictureAttributeSupported_None); 00253 } 00254 else 00255 { 00256 LOG(VB_GENERAL, LOG_ERR, LOC + "Fatal error"); 00257 Teardown(); 00258 return false; 00259 } 00260 } 00261 00262 bool mmx = false; 00263 #ifdef MMX 00264 mmx = true; 00265 #endif 00266 00267 CheckResize(false); 00268 00269 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("MMX: %1 PBO: %2") 00270 .arg(mmx).arg((gl_features & kGLExtPBufObj) > 0)); 00271 00272 return true; 00273 } 00274 00280 void OpenGLVideo::CheckResize(bool deinterlacing, bool allow) 00281 { 00282 // to improve performance on slower cards 00283 bool resize_up = ((video_disp_dim.height() < display_video_rect.height()) || 00284 (video_disp_dim.width() < display_video_rect.width())) && allow; 00285 00286 // to ensure deinterlacing works correctly 00287 bool resize_down = (video_disp_dim.height() > display_video_rect.height()) && 00288 deinterlacing && allow; 00289 00290 // UYVY packed pixels must be sampled exactly and any overscan settings will 00291 // break sampling - so always force an extra stage 00292 resize_down |= videoTextureType == MYTHTV_UYVY; 00293 00294 if (resize_up && (defaultUpsize == kGLFilterBicubic)) 00295 { 00296 RemoveFilter(kGLFilterResize); 00297 filters.erase(kGLFilterResize); 00298 AddFilter(kGLFilterBicubic); 00299 OptimiseFilters(); 00300 return; 00301 } 00302 00303 if ((resize_up && (defaultUpsize == kGLFilterResize)) || resize_down) 00304 { 00305 RemoveFilter(kGLFilterBicubic); 00306 filters.erase(kGLFilterBicubic); 00307 AddFilter(kGLFilterResize); 00308 OptimiseFilters(); 00309 return; 00310 } 00311 00312 RemoveFilter(kGLFilterBicubic); 00313 filters.erase(kGLFilterBicubic); 00314 OptimiseFilters(); 00315 } 00316 00323 bool OpenGLVideo::OptimiseFilters(void) 00324 { 00325 glfilt_map_t::reverse_iterator it; 00326 00327 // add/remove required frame buffer objects 00328 // and link filters 00329 uint buffers_needed = 1; 00330 bool last_filter = true; 00331 for (it = filters.rbegin(); it != filters.rend(); ++it) 00332 { 00333 if (!last_filter) 00334 { 00335 it->second->outputBuffer = kFrameBufferObject; 00336 uint buffers_have = it->second->frameBuffers.size(); 00337 int buffers_diff = buffers_needed - buffers_have; 00338 if (buffers_diff > 0) 00339 { 00340 uint tmp_buf, tmp_tex; 00341 for (int i = 0; i < buffers_diff; i++) 00342 { 00343 if (!AddFrameBuffer(tmp_buf, tmp_tex, video_disp_dim)) 00344 return false; 00345 else 00346 { 00347 it->second->frameBuffers.push_back(tmp_buf); 00348 it->second->frameBufferTextures.push_back(tmp_tex); 00349 } 00350 } 00351 } 00352 else if (buffers_diff < 0) 00353 { 00354 for (int i = 0; i > buffers_diff; i--) 00355 { 00356 OpenGLFilter *filt = it->second; 00357 00358 gl_context->DeleteFrameBuffer( 00359 filt->frameBuffers.back()); 00360 gl_context->DeleteTexture( 00361 filt->frameBufferTextures.back()); 00362 00363 filt->frameBuffers.pop_back(); 00364 filt->frameBufferTextures.pop_back(); 00365 } 00366 } 00367 } 00368 else 00369 { 00370 it->second->outputBuffer = kDefaultBuffer; 00371 last_filter = false; 00372 } 00373 buffers_needed = it->second->numInputs; 00374 } 00375 00376 SetFiltering(); 00377 00378 return true; 00379 } 00380 00386 void OpenGLVideo::SetFiltering(void) 00387 { 00388 if (filters.size() < 2) 00389 { 00390 SetTextureFilters(&inputTextures, GL_LINEAR, GL_CLAMP_TO_EDGE); 00391 SetTextureFilters(&referenceTextures, GL_LINEAR, GL_CLAMP_TO_EDGE); 00392 return; 00393 } 00394 00395 SetTextureFilters(&inputTextures, GL_NEAREST, GL_CLAMP_TO_EDGE); 00396 SetTextureFilters(&referenceTextures, GL_NEAREST, GL_CLAMP_TO_EDGE); 00397 00398 glfilt_map_t::reverse_iterator rit; 00399 int last_filter = 0; 00400 00401 for (rit = filters.rbegin(); rit != filters.rend(); ++rit) 00402 { 00403 if (last_filter == 1) 00404 { 00405 SetTextureFilters(&(rit->second->frameBufferTextures), 00406 GL_LINEAR, GL_CLAMP_TO_EDGE); 00407 } 00408 else if (last_filter > 1) 00409 { 00410 SetTextureFilters(&(rit->second->frameBufferTextures), 00411 GL_NEAREST, GL_CLAMP_TO_EDGE); 00412 } 00413 ++last_filter; 00414 } 00415 } 00416 00422 bool OpenGLVideo::AddFilter(OpenGLFilterType filter) 00423 { 00424 if (filters.count(filter)) 00425 return true; 00426 00427 if (!(gl_features & kGLExtFBufObj) && (filter == kGLFilterResize) && 00428 !filters.empty()) 00429 { 00430 LOG(VB_PLAYBACK, LOG_ERR, LOC + 00431 "GL_EXT_framebuffer_object not available " 00432 "for scaling/resizing filter."); 00433 return false; 00434 } 00435 00436 if (!((gl_features & kGLExtFragProg) && (gl_features & kGLExtFBufObj)) && 00437 filter == kGLFilterBicubic) 00438 { 00439 LOG(VB_PLAYBACK, LOG_ERR, LOC + 00440 "Features not available for bicubic filter."); 00441 return false; 00442 } 00443 00444 if (!(gl_features & kGLExtFragProg) && !(gl_features & kGLSL) && 00445 (filter == kGLFilterYUV2RGB)) 00446 { 00447 LOG(VB_PLAYBACK, LOG_ERR, LOC + 00448 "No shader support for OpenGL deinterlacing."); 00449 return false; 00450 } 00451 00452 bool success = true; 00453 00454 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Creating %1 filter.") 00455 .arg(FilterToString(filter))); 00456 00457 OpenGLFilter *temp = new OpenGLFilter(); 00458 00459 temp->numInputs = 1; 00460 GLuint program = 0; 00461 00462 if (filter == kGLFilterBicubic) 00463 { 00464 if (helperTexture) 00465 gl_context->DeleteTexture(helperTexture); 00466 00467 helperTexture = gl_context->CreateHelperTexture(); 00468 if (!helperTexture) 00469 success = false; 00470 } 00471 00472 if (success && (filter != kGLFilterNone) && (filter != kGLFilterResize)) 00473 { 00474 program = AddFragmentProgram(filter); 00475 if (!program) 00476 success = false; 00477 else 00478 temp->fragmentPrograms.push_back(program); 00479 } 00480 00481 if (success) 00482 { 00483 temp->outputBuffer = kDefaultBuffer; 00484 temp->frameBuffers.clear(); 00485 temp->frameBufferTextures.clear(); 00486 filters[filter] = temp; 00487 success &= OptimiseFilters(); 00488 } 00489 00490 if (!success) 00491 { 00492 RemoveFilter(filter); 00493 filters.erase(filter); 00494 delete temp; // If temp wasn't added to the filter list, we need to delete 00495 return false; 00496 } 00497 00498 return true; 00499 } 00500 00501 bool OpenGLVideo::RemoveFilter(OpenGLFilterType filter) 00502 { 00503 if (!filters.count(filter)) 00504 return true; 00505 00506 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Removing %1 filter") 00507 .arg(FilterToString(filter))); 00508 00509 vector<GLuint> temp; 00510 vector<GLuint>::iterator it; 00511 00512 temp = filters[filter]->fragmentPrograms; 00513 for (it = temp.begin(); it != temp.end(); ++it) 00514 gl_context->DeleteShaderObject(*it); 00515 filters[filter]->fragmentPrograms.clear(); 00516 00517 temp = filters[filter]->frameBuffers; 00518 for (it = temp.begin(); it != temp.end(); ++it) 00519 gl_context->DeleteFrameBuffer(*it); 00520 filters[filter]->frameBuffers.clear(); 00521 00522 DeleteTextures(&(filters[filter]->frameBufferTextures)); 00523 00524 delete filters[filter]; 00525 filters[filter] = NULL; 00526 00527 return true; 00528 } 00529 00530 void OpenGLVideo::TearDownDeinterlacer(void) 00531 { 00532 if (!filters.count(kGLFilterYUV2RGB)) 00533 return; 00534 00535 OpenGLFilter *tmp = filters[kGLFilterYUV2RGB]; 00536 00537 if (tmp->fragmentPrograms.size() == 3) 00538 { 00539 gl_context->DeleteShaderObject(tmp->fragmentPrograms[2]); 00540 tmp->fragmentPrograms.pop_back(); 00541 } 00542 00543 if (tmp->fragmentPrograms.size() == 2) 00544 { 00545 gl_context->DeleteShaderObject(tmp->fragmentPrograms[1]); 00546 tmp->fragmentPrograms.pop_back(); 00547 } 00548 00549 DeleteTextures(&referenceTextures); 00550 refsNeeded = 0; 00551 } 00552 00561 bool OpenGLVideo::AddDeinterlacer(const QString &deinterlacer) 00562 { 00563 if (!(gl_features & kGLExtFragProg) && !(gl_features & kGLSL)) 00564 { 00565 LOG(VB_PLAYBACK, LOG_ERR, LOC + 00566 "No shader support for OpenGL deinterlacing."); 00567 return false; 00568 } 00569 00570 OpenGLLocker ctx_lock(gl_context); 00571 00572 if (!filters.count(kGLFilterYUV2RGB)) 00573 { 00574 LOG(VB_PLAYBACK, LOG_ERR, LOC + 00575 "No YUV2RGB filter stage for OpenGL deinterlacing%1."); 00576 return false; 00577 } 00578 00579 if (hardwareDeinterlacer == deinterlacer) 00580 return true; 00581 00582 TearDownDeinterlacer(); 00583 00584 bool success = true; 00585 00586 uint ref_size = 2; 00587 00588 if (deinterlacer == "openglbobdeint" || 00589 deinterlacer == "openglonefield" || 00590 deinterlacer == "opengllinearblend" || 00591 deinterlacer == "opengldoubleratelinearblend" || 00592 deinterlacer == "opengldoubleratefieldorder") 00593 { 00594 ref_size = 0; 00595 } 00596 00597 refsNeeded = ref_size; 00598 if (ref_size > 0) 00599 { 00600 for (; ref_size > 0; ref_size--) 00601 { 00602 GLuint tex = CreateVideoTexture(video_dim, inputTextureSize); 00603 if (tex) 00604 { 00605 referenceTextures.push_back(tex); 00606 } 00607 else 00608 { 00609 success = false; 00610 } 00611 } 00612 } 00613 00614 uint prog1 = AddFragmentProgram(kGLFilterYUV2RGB, 00615 deinterlacer, kScan_Interlaced); 00616 uint prog2 = AddFragmentProgram(kGLFilterYUV2RGB, 00617 deinterlacer, kScan_Intr2ndField); 00618 00619 if (prog1 && prog2) 00620 { 00621 filters[kGLFilterYUV2RGB]->fragmentPrograms.push_back(prog1); 00622 filters[kGLFilterYUV2RGB]->fragmentPrograms.push_back(prog2); 00623 } 00624 else 00625 { 00626 success = false; 00627 } 00628 00629 if (success) 00630 { 00631 CheckResize(hardwareDeinterlacing); 00632 hardwareDeinterlacer = deinterlacer; 00633 return true; 00634 } 00635 00636 hardwareDeinterlacer = ""; 00637 TearDownDeinterlacer(); 00638 00639 return false; 00640 } 00641 00648 uint OpenGLVideo::AddFragmentProgram(OpenGLFilterType name, 00649 QString deint, FrameScanType field) 00650 { 00651 if (!gl_context) 00652 return 0; 00653 00654 QString vertex, fragment; 00655 if (gl_features & kGLSL) 00656 { 00657 GetProgramStrings(vertex, fragment, name, deint, field); 00658 } 00659 else if (gl_features & kGLExtFragProg) 00660 { 00661 fragment = GetProgramString(name, deint, field); 00662 } 00663 else 00664 { 00665 LOG(VB_PLAYBACK, LOG_ERR, LOC + "No OpenGL shader/program support"); 00666 return 0; 00667 } 00668 00669 return gl_context->CreateShaderObject(vertex, fragment); 00670 } 00671 00678 bool OpenGLVideo::AddFrameBuffer(uint &framebuffer, 00679 uint &texture, QSize vid_size) 00680 { 00681 if (!(gl_features & kGLExtFBufObj)) 00682 { 00683 LOG(VB_PLAYBACK, LOG_ERR, LOC + "Framebuffer binding not supported."); 00684 return false; 00685 } 00686 00687 texture = gl_context->CreateTexture(vid_size, false, textureType); 00688 00689 bool ok = gl_context->CreateFrameBuffer(framebuffer, texture); 00690 00691 if (!ok) 00692 gl_context->DeleteTexture(texture); 00693 00694 return ok; 00695 } 00696 00697 void OpenGLVideo::SetViewPort(const QSize &viewPortSize) 00698 { 00699 uint w = max(viewPortSize.width(), video_disp_dim.width()); 00700 uint h = max(viewPortSize.height(), video_disp_dim.height()); 00701 00702 viewportSize = QSize(w, h); 00703 00704 if (!viewportControl) 00705 return; 00706 00707 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Viewport: %1x%2") .arg(w).arg(h)); 00708 gl_context->SetViewPort(QRect(QPoint(),viewportSize)); 00709 } 00710 00717 uint OpenGLVideo::CreateVideoTexture(QSize size, QSize &tex_size) 00718 { 00719 uint tmp_tex = 0; 00720 bool use_pbo = gl_features & kGLExtPBufObj; 00721 if (GL_YCBCR_MESA == videoTextureType) 00722 { 00723 tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType, 00724 GL_UNSIGNED_SHORT_8_8_MESA, 00725 GL_YCBCR_MESA, GL_YCBCR_MESA); 00726 } 00727 else if (GL_YCBCR_422_APPLE == videoTextureType) 00728 { 00729 tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType, 00730 GL_UNSIGNED_SHORT_8_8_MESA, 00731 GL_YCBCR_422_APPLE, GL_RGBA); 00732 } 00733 else if (MYTHTV_UYVY == videoTextureType) 00734 { 00735 QSize fix(size.width() / 2, size.height()); 00736 tmp_tex = gl_context->CreateTexture(fix, use_pbo, textureType, 00737 GL_UNSIGNED_BYTE, GL_RGBA, GL_RGBA); 00738 } 00739 else 00740 tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType); 00741 00742 tex_size = gl_context->GetTextureSize(textureType, size); 00743 if (!tmp_tex) 00744 return 0; 00745 00746 return tmp_tex; 00747 } 00748 00749 QSize OpenGLVideo::GetTextureSize(const QSize &size) 00750 { 00751 if (textureRects) 00752 return size; 00753 00754 int w = 64; 00755 int h = 64; 00756 00757 while (w < size.width()) 00758 { 00759 w *= 2; 00760 } 00761 00762 while (h < size.height()) 00763 { 00764 h *= 2; 00765 } 00766 00767 return QSize(w, h); 00768 } 00769 00770 uint OpenGLVideo::GetInputTexture(void) const 00771 { 00772 return inputTextures[0]; 00773 } 00774 00775 uint OpenGLVideo::GetTextureType(void) const 00776 { 00777 return textureType; 00778 } 00779 00780 void OpenGLVideo::SetInputUpdated(void) 00781 { 00782 inputUpdated = true; 00783 } 00784 00792 void OpenGLVideo::UpdateInputFrame(const VideoFrame *frame, bool soft_bob) 00793 { 00794 OpenGLLocker ctx_lock(gl_context); 00795 00796 if (frame->width != video_dim.width() || 00797 frame->height != video_dim.height() || 00798 frame->width < 1 || frame->height < 1 || 00799 frame->codec != FMT_YV12) 00800 { 00801 return; 00802 } 00803 if (hardwareDeinterlacing) 00804 RotateTextures(); 00805 00806 // We need to convert frames here to avoid dependencies in MythRenderOpenGL 00807 void* buf = gl_context->GetTextureBuffer(inputTextures[0]); 00808 if (!buf) 00809 return; 00810 00811 if (!filters.count(kGLFilterYUV2RGB) || 00812 MYTHTV_UYVY == videoTextureType) 00813 { 00814 // software conversion 00815 AVPicture img_in, img_out; 00816 PixelFormat out_fmt = PIX_FMT_BGRA; 00817 if ((GL_YCBCR_MESA == videoTextureType) || 00818 (GL_YCBCR_422_APPLE == videoTextureType) || 00819 (MYTHTV_UYVY == videoTextureType)) 00820 { 00821 out_fmt = PIX_FMT_UYVY422; 00822 } 00823 00824 avpicture_fill(&img_out, (uint8_t *)buf, out_fmt, 00825 frame->width, frame->height); 00826 avpicture_fill(&img_in, (uint8_t *)frame->buf, PIX_FMT_YUV420P, 00827 frame->width, frame->height); 00828 myth_sws_img_convert(&img_out, out_fmt, &img_in, PIX_FMT_YUV420P, 00829 frame->width, frame->height); 00830 } 00831 else if (frame->interlaced_frame && !soft_bob) 00832 { 00833 pack_yv12interlaced(frame->buf, (unsigned char*)buf, frame->offsets, 00834 frame->pitches, video_dim); 00835 } 00836 else 00837 { 00838 pack_yv12progressive(frame->buf, (unsigned char*)buf, frame->offsets, 00839 frame->pitches, video_dim); 00840 } 00841 00842 gl_context->UpdateTexture(inputTextures[0], buf); 00843 inputUpdated = true; 00844 } 00845 00846 void OpenGLVideo::SetDeinterlacing(bool deinterlacing) 00847 { 00848 hardwareDeinterlacing = deinterlacing; 00849 OpenGLLocker ctx_lock(gl_context); 00850 CheckResize(hardwareDeinterlacing); 00851 } 00852 00853 void OpenGLVideo::SetSoftwareDeinterlacer(const QString &filter) 00854 { 00855 if (softwareDeinterlacer != filter) 00856 CheckResize(false, filter != "bobdeint"); 00857 softwareDeinterlacer = filter; 00858 softwareDeinterlacer.detach(); 00859 } 00860 00877 void OpenGLVideo::PrepareFrame(bool topfieldfirst, FrameScanType scan, 00878 bool softwareDeinterlacing, 00879 long long frame, StereoscopicMode stereo, 00880 bool draw_border) 00881 { 00882 if (inputTextures.empty() || filters.empty()) 00883 return; 00884 00885 OpenGLLocker ctx_lock(gl_context); 00886 00887 // we need to special case software bobdeint for 1080i 00888 bool softwarebob = softwareDeinterlacer == "bobdeint" && 00889 softwareDeinterlacing; 00890 00891 vector<GLuint> inputs = inputTextures; 00892 QSize inputsize = inputTextureSize; 00893 QSize realsize = GetTextureSize(video_disp_dim); 00894 00895 glfilt_map_t::iterator it; 00896 for (it = filters.begin(); it != filters.end(); ++it) 00897 { 00898 OpenGLFilterType type = it->first; 00899 OpenGLFilter *filter = it->second; 00900 00901 bool actual = softwarebob && (filter->outputBuffer == kDefaultBuffer); 00902 00903 // texture coordinates 00904 float trueheight = (float)(actual ? video_dim.height() : 00905 video_disp_dim.height()); 00906 float width = video_disp_dim.width(); 00907 if ((type == kGLFilterYUV2RGB) && (videoTextureType == MYTHTV_UYVY)) 00908 width /= 2.0f; 00909 00910 QRectF trect(QPoint(0, 0), QSize(width, trueheight)); 00911 00912 // only apply overscan on last filter 00913 if (filter->outputBuffer == kDefaultBuffer) 00914 trect.setCoords(video_rect.left(), video_rect.top(), 00915 video_rect.left() + video_rect.width(), 00916 video_rect.top() + video_rect.height()); 00917 00918 if (!textureRects && (inputsize.height() > 0)) 00919 trueheight /= inputsize.height(); 00920 00921 // software bobdeint 00922 if (actual) 00923 { 00924 bool top = (scan == kScan_Intr2ndField && topfieldfirst) || 00925 (scan == kScan_Interlaced && !topfieldfirst); 00926 bool bot = (scan == kScan_Interlaced && topfieldfirst) || 00927 (scan == kScan_Intr2ndField && !topfieldfirst); 00928 bool first = filters.size() < 2; 00929 float bob = (trueheight / (float)video_disp_dim.height()) / 4.0f; 00930 if ((top && !first) || (bot && first)) 00931 { 00932 trect.setBottom(trect.bottom() / 2); 00933 trect.setTop(trect.top() / 2); 00934 trect.adjust(0, bob, 0, bob); 00935 } 00936 if ((bot && !first) || (top && first)) 00937 { 00938 trect.setTop((trueheight / 2) + (trect.top() / 2)); 00939 trect.setBottom((trueheight / 2) + (trect.bottom() / 2)); 00940 trect.adjust(0, -bob, 0, -bob); 00941 } 00942 } 00943 00944 // discard stereoscopic fields 00945 if (filter->outputBuffer == kDefaultBuffer) 00946 { 00947 if (kStereoscopicModeSideBySideDiscard == stereo) 00948 trect = QRectF(trect.left() / 2.0f, trect.top(), 00949 trect.width() / 2.0f, trect.height()); 00950 if (kStereoscopicModeTopAndBottomDiscard == stereo) 00951 trect = QRectF(trect.left(), trect.top() / 2.0f, 00952 trect.width(), trect.height() / 2.0f); 00953 } 00954 00955 // vertex coordinates 00956 QRect display = (filter->outputBuffer == kDefaultBuffer) ? 00957 display_video_rect : frameBufferRect; 00958 QRect visible = (filter->outputBuffer == kDefaultBuffer) ? 00959 display_visible_rect : frameBufferRect; 00960 QRectF vrect(display); 00961 00962 // invert if first filter 00963 if (it == filters.begin()) 00964 { 00965 if (filters.size() > 1) 00966 { 00967 vrect.setTop((visible.height()) - display.top()); 00968 vrect.setBottom(vrect.top() - (display.height())); 00969 } 00970 else 00971 { 00972 vrect.setBottom(display.top()); 00973 vrect.setTop(display.top() + (display.height())); 00974 } 00975 } 00976 00977 // hardware bobdeint 00978 if (filter->outputBuffer == kDefaultBuffer && 00979 hardwareDeinterlacing && 00980 hardwareDeinterlacer == "openglbobdeint") 00981 { 00982 float bob = ((float)display.height() / (float)video_rect.height()) 00983 / 2.0f; 00984 float field = kScan_Interlaced ? -1.0f : 1.0f; 00985 bob = bob * (topfieldfirst ? field : -field); 00986 vrect.adjust(0, bob, 0, bob); 00987 } 00988 00989 uint target = 0; 00990 // bind correct frame buffer (default onscreen) and set viewport 00991 switch (filter->outputBuffer) 00992 { 00993 case kDefaultBuffer: 00994 gl_context->BindFramebuffer(0); 00995 if (viewportControl) 00996 gl_context->SetViewPort(QRect(QPoint(), display_visible_rect.size())); 00997 else 00998 gl_context->SetViewPort(QRect(QPoint(), masterViewportSize)); 00999 break; 01000 case kFrameBufferObject: 01001 if (!filter->frameBuffers.empty()) 01002 { 01003 gl_context->BindFramebuffer(filter->frameBuffers[0]); 01004 gl_context->SetViewPort(QRect(QPoint(), frameBufferRect.size())); 01005 target = filter->frameBuffers[0]; 01006 } 01007 break; 01008 01009 default: 01010 continue; 01011 } 01012 01013 if (draw_border && filter->outputBuffer == kDefaultBuffer) 01014 { 01015 QRectF piprectf = vrect.adjusted(-10, -10, +10, +10); 01016 QRect piprect(piprectf.left(), piprectf.top(), 01017 piprectf.width(), piprectf.height()); 01018 static const QPen nopen(Qt::NoPen); 01019 static const QBrush redbrush(QBrush(QColor(127, 0, 0, 255))); 01020 gl_context->DrawRect(piprect, redbrush, nopen, 255); 01021 } 01022 01023 // bind correct textures 01024 uint textures[4]; // NB 01025 uint texture_count = 0; 01026 for (uint i = 0; i < inputs.size(); i++) 01027 textures[texture_count++] = inputs[i]; 01028 01029 if (!referenceTextures.empty() && 01030 hardwareDeinterlacing && 01031 type == kGLFilterYUV2RGB) 01032 { 01033 for (uint i = 0; i < referenceTextures.size(); i++) 01034 textures[texture_count++] = referenceTextures[i]; 01035 } 01036 01037 if (helperTexture && type == kGLFilterBicubic) 01038 textures[texture_count++] = helperTexture; 01039 01040 // enable fragment program and set any environment variables 01041 GLuint program = 0; 01042 if ((type != kGLFilterNone) && (type != kGLFilterResize)) 01043 { 01044 GLuint prog_ref = 0; 01045 01046 if (type == kGLFilterYUV2RGB) 01047 { 01048 if (hardwareDeinterlacing && 01049 filter->fragmentPrograms.size() == 3 && 01050 !refsNeeded) 01051 { 01052 if (scan == kScan_Interlaced) 01053 prog_ref = topfieldfirst ? 1 : 2; 01054 else if (scan == kScan_Intr2ndField) 01055 prog_ref = topfieldfirst ? 2 : 1; 01056 } 01057 } 01058 program = filter->fragmentPrograms[prog_ref]; 01059 } 01060 01061 if (type == kGLFilterYUV2RGB) 01062 gl_context->SetShaderParams(program, colourSpace->GetMatrix(), 01063 COLOUR_UNIFORM); 01064 01065 gl_context->DrawBitmap(textures, texture_count, target, &trect, &vrect, 01066 program); 01067 01068 inputs = filter->frameBufferTextures; 01069 inputsize = realsize; 01070 } 01071 01072 currentFrameNum = frame; 01073 inputUpdated = false; 01074 } 01075 01076 void OpenGLVideo::RotateTextures(void) 01077 { 01078 if (referenceTextures.size() < 2) 01079 return; 01080 01081 if (refsNeeded > 0) 01082 refsNeeded--; 01083 01084 GLuint tmp = referenceTextures[referenceTextures.size() - 1]; 01085 01086 for (uint i = referenceTextures.size() - 1; i > 0; i--) 01087 referenceTextures[i] = referenceTextures[i - 1]; 01088 01089 referenceTextures[0] = inputTextures[0]; 01090 inputTextures[0] = tmp; 01091 } 01092 01093 void OpenGLVideo::DeleteTextures(vector<GLuint> *textures) 01094 { 01095 if ((*textures).empty()) 01096 return; 01097 01098 for (uint i = 0; i < (*textures).size(); i++) 01099 gl_context->DeleteTexture((*textures)[i]); 01100 (*textures).clear(); 01101 } 01102 01103 void OpenGLVideo::SetTextureFilters(vector<GLuint> *textures, 01104 int filt, int wrap) 01105 { 01106 if (textures->empty()) 01107 return; 01108 01109 for (uint i = 0; i < textures->size(); i++) 01110 gl_context->SetTextureFilters((*textures)[i], filt, wrap); 01111 } 01112 01113 OpenGLFilterType OpenGLVideo::StringToFilter(const QString &filter) 01114 { 01115 OpenGLFilterType ret = kGLFilterNone; 01116 01117 if (filter.contains("master")) 01118 ret = kGLFilterYUV2RGB; 01119 else if (filter.contains("resize")) 01120 ret = kGLFilterResize; 01121 else if (filter.contains("bicubic")) 01122 ret = kGLFilterBicubic; 01123 01124 return ret; 01125 } 01126 01127 QString OpenGLVideo::FilterToString(OpenGLFilterType filt) 01128 { 01129 switch (filt) 01130 { 01131 case kGLFilterNone: 01132 break; 01133 case kGLFilterYUV2RGB: 01134 return "master"; 01135 case kGLFilterResize: 01136 return "resize"; 01137 case kGLFilterBicubic: 01138 return "bicubic"; 01139 } 01140 01141 return ""; 01142 } 01143 01144 static const QString attrib_fast = 01145 "ATTRIB tex = fragment.texcoord[0];\n" 01146 "PARAM yuv[3] = { program.local[0..2] };\n"; 01147 01148 static const QString tex_fast = 01149 "TEX res, tex, texture[0], %1;\n"; 01150 01151 static const QString var_fast = 01152 "TEMP tmp, res;\n"; 01153 01154 static const QString var_col = 01155 "TEMP col;\n"; 01156 01157 static const QString select_col = 01158 "MUL col, tex.xxxx, %8;\n" 01159 "FRC col, col;\n" 01160 "SUB col, col, 0.5;\n" 01161 "CMP res, col, res.rabg, res.rgba;\n"; 01162 01163 static const QString end_fast = 01164 "DPH tmp.r, res.arbg, yuv[0];\n" 01165 "DPH tmp.g, res.arbg, yuv[1];\n" 01166 "DPH tmp.b, res.arbg, yuv[2];\n" 01167 "MOV tmp.a, 1.0;\n" 01168 "MOV result.color, tmp;\n"; 01169 01170 static const QString var_deint = 01171 "TEMP other, current, mov, prev;\n"; 01172 01173 static const QString field_calc = 01174 "MUL prev, tex.yyyy, %2;\n" 01175 "FRC prev, prev;\n" 01176 "SUB prev, prev, 0.5;\n"; 01177 01178 static const QString bobdeint[2] = { 01179 field_calc + 01180 "ADD other, tex, {0.0, %3, 0.0, 0.0};\n" 01181 "MIN other, other, {10000.0, %9, 10000.0, 10000.0};\n" 01182 "TEX other, other, texture[0], %1;\n" 01183 "CMP res, prev, res, other;\n", 01184 field_calc + 01185 "SUB other, tex, {0.0, %3, 0.0, 0.0};\n" 01186 "TEX other, other, texture[0], %1;\n" 01187 "CMP res, prev, other, res;\n" 01188 }; 01189 01190 static const QString deint_end_top = 01191 "CMP res, prev, current, other;\n"; 01192 01193 static const QString deint_end_bot = 01194 "CMP res, prev, other, current;\n"; 01195 01196 static const QString linearblend[2] = { 01197 "TEX current, tex, texture[0], %1;\n" 01198 "ADD other, tex, {0.0, %3, 0.0, 0.0};\n" 01199 "MIN other, other, {10000.0, %9, 10000.0, 10000.0};\n" 01200 "TEX other, other, texture[0], %1;\n" 01201 "SUB mov, tex, {0.0, %3, 0.0, 0.0};\n" 01202 "TEX mov, mov, texture[0], %1;\n" 01203 "LRP other, 0.5, other, mov;\n" 01204 + field_calc + deint_end_top, 01205 01206 "TEX current, tex, texture[0], %1;\n" 01207 "SUB other, tex, {0.0, %3, 0.0, 0.0};\n" 01208 "TEX other, other, texture[0], %1;\n" 01209 "ADD mov, tex, {0.0, %3, 0.0, 0.0};\n" 01210 "TEX mov, mov, texture[0], %1;\n" 01211 "LRP other, 0.5, other, mov;\n" 01212 + field_calc + deint_end_bot 01213 }; 01214 01215 static const QString kerneldeint[2] = { 01216 "TEX current, tex, texture[1], %1;\n" 01217 "TEX prev, tex, texture[2], %1;\n" 01218 "MUL other, 0.125, prev;\n" 01219 "MAD other, 0.125, current, other;\n" 01220 "ADD prev, tex, {0.0, %3, 0.0, 0.0};\n" 01221 "MIN prev, prev, {10000.0, %9, 10000.0, 10000.0};\n" 01222 "TEX prev, prev, texture[1], %1;\n" 01223 "MAD other, 0.5, prev, other;\n" 01224 "SUB prev, tex, {0.0, %3, 0.0, 0.0};\n" 01225 "TEX prev, prev, texture[1], %1;\n" 01226 "MAD other, 0.5, prev, other;\n" 01227 "ADD prev, tex, {0.0, %4, 0.0, 0.0};\n" 01228 "TEX tmp, prev, texture[1], %1;\n" 01229 "MAD other, -0.0625, tmp, other;\n" 01230 "TEX tmp, prev, texture[2], %1;\n" 01231 "MAD other, -0.0625, tmp, other;\n" 01232 "SUB prev, tex, {0.0, %4, 0.0, 0.0};\n" 01233 "TEX tmp, prev, texture[1], %1;\n" 01234 "MAD other, -0.0625, tmp, other;\n" 01235 "TEX tmp, prev, texture[2], %1;\n" 01236 "MAD other, -0.0625, tmp, other;\n" 01237 + field_calc + deint_end_top, 01238 01239 "TEX current, tex, texture[1], %1;\n" 01240 "MUL other, 0.125, res;\n" 01241 "MAD other, 0.125, current, other;\n" 01242 "ADD prev, tex, {0.0, %3, 0.0, 0.0};\n" 01243 "TEX prev, prev, texture[1], %1;\n" 01244 "MAD other, 0.5, prev, other;\n" 01245 "SUB prev, tex, {0.0, %3, 0.0, 0.0};\n" 01246 "TEX prev, prev, texture[1], %1;\n" 01247 "MAD other, 0.5, prev, other;\n" 01248 "ADD prev, tex, {0.0, %4, 0.0, 0.0};\n" 01249 "TEX tmp, prev, texture[1], %1;\n" 01250 "MAD other, -0.0625, tmp, other;\n" 01251 "TEX tmp, prev, texture[0], %1;\n" 01252 "MAD other, -0.0625, tmp, other;\n" 01253 "SUB prev, tex, {0.0, %4, 0.0, 0.0};\n" 01254 "TEX tmp, prev, texture[1], %1;\n" 01255 "MAD other, -0.0625, tmp, other;\n" 01256 "TEX tmp, prev, texture[0], %1;\n" 01257 "MAD other, -0.0625, tmp, other;\n" 01258 + field_calc + deint_end_bot 01259 }; 01260 01261 static const QString bicubic = 01262 "TEMP coord, coord2, cdelta, parmx, parmy, a, b, c, d;\n" 01263 "MAD coord.xy, fragment.texcoord[0], {%6, %7}, {0.5, 0.5};\n" 01264 "TEX parmx, coord.x, texture[1], 1D;\n" 01265 "TEX parmy, coord.y, texture[1], 1D;\n" 01266 "MUL cdelta.xz, parmx.rrgg, {-%5, 0, %5, 0};\n" 01267 "MUL cdelta.yw, parmy.rrgg, {0, -%3, 0, %3};\n" 01268 "ADD coord, fragment.texcoord[0].xyxy, cdelta.xyxw;\n" 01269 "ADD coord2, fragment.texcoord[0].xyxy, cdelta.zyzw;\n" 01270 "TEX a, coord.xyxy, texture[0], 2D;\n" 01271 "TEX b, coord.zwzw, texture[0], 2D;\n" 01272 "TEX c, coord2.xyxy, texture[0], 2D;\n" 01273 "TEX d, coord2.zwzw, texture[0], 2D;\n" 01274 "LRP a, parmy.b, a, b;\n" 01275 "LRP c, parmy.b, c, d;\n" 01276 "LRP result.color, parmx.b, a, c;\n"; 01277 01278 QString OpenGLVideo::GetProgramString(OpenGLFilterType name, 01279 QString deint, FrameScanType field) 01280 { 01281 QString ret = 01282 "!!ARBfp1.0\n" 01283 "OPTION ARB_precision_hint_fastest;\n"; 01284 01285 switch (name) 01286 { 01287 case kGLFilterYUV2RGB: 01288 { 01289 bool need_tex = true; 01290 bool packed = MYTHTV_UYVY == videoTextureType; 01291 QString deint_bit = ""; 01292 if (deint != "") 01293 { 01294 uint tmp_field = 0; 01295 if (field == kScan_Intr2ndField) 01296 tmp_field = 1; 01297 if (deint == "openglbobdeint" || 01298 deint == "openglonefield" || 01299 deint == "opengldoubleratefieldorder") 01300 { 01301 deint_bit = bobdeint[tmp_field]; 01302 } 01303 else if (deint == "opengllinearblend" || 01304 deint == "opengldoubleratelinearblend") 01305 { 01306 deint_bit = linearblend[tmp_field]; 01307 if (!tmp_field) { need_tex = false; } 01308 } 01309 else if (deint == "openglkerneldeint" || 01310 deint == "opengldoubleratekerneldeint") 01311 { 01312 deint_bit = kerneldeint[tmp_field]; 01313 if (!tmp_field) { need_tex = false; } 01314 } 01315 else 01316 { 01317 LOG(VB_PLAYBACK, LOG_ERR, LOC + 01318 "Unrecognised OpenGL deinterlacer"); 01319 } 01320 } 01321 01322 ret += attrib_fast; 01323 ret += (deint != "") ? var_deint : ""; 01324 ret += packed ? var_col : ""; 01325 ret += var_fast + (need_tex ? tex_fast : ""); 01326 ret += deint_bit; 01327 ret += packed ? select_col : ""; 01328 ret += end_fast; 01329 } 01330 break; 01331 01332 case kGLFilterNone: 01333 case kGLFilterResize: 01334 break; 01335 01336 case kGLFilterBicubic: 01337 01338 ret += bicubic; 01339 break; 01340 01341 default: 01342 LOG(VB_PLAYBACK, LOG_ERR, LOC + "Unknown fragment program."); 01343 break; 01344 } 01345 01346 CustomiseProgramString(ret); 01347 ret += "END"; 01348 01349 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created %1 fragment program %2") 01350 .arg(FilterToString(name)).arg(deint)); 01351 01352 return ret; 01353 } 01354 01355 void OpenGLVideo::CustomiseProgramString(QString &string) 01356 { 01357 string.replace("%1", textureRects ? "RECT" : "2D"); 01358 01359 if (!textureRects) 01360 { 01361 string.replace("GLSL_SAMPLER", "sampler2D"); 01362 string.replace("GLSL_TEXTURE", "texture2D"); 01363 } 01364 01365 float lineHeight = 1.0f; 01366 float colWidth = 1.0f; 01367 float yselect = 1.0f; 01368 QSize fb_size = GetTextureSize(video_disp_dim); 01369 01370 if (!textureRects && 01371 (inputTextureSize.height() > 0)) 01372 { 01373 lineHeight /= inputTextureSize.height(); 01374 colWidth /= inputTextureSize.width(); 01375 yselect /= ((float)inputTextureSize.width() / 2.0f); 01376 } 01377 01378 float maxheight = (float)(min(inputTextureSize.height(), 1080) - 1) * 01379 lineHeight; 01380 float fieldSize = 1.0f / (lineHeight * 2.0); 01381 01382 string.replace("%2", QString::number(fieldSize, 'f', 8)); 01383 string.replace("%3", QString::number(lineHeight, 'f', 8)); 01384 string.replace("%4", QString::number(lineHeight * 2.0, 'f', 8)); 01385 string.replace("%5", QString::number(colWidth, 'f', 8)); 01386 string.replace("%6", QString::number((float)fb_size.width(), 'f', 1)); 01387 string.replace("%7", QString::number((float)fb_size.height(), 'f', 1)); 01388 string.replace("%8", QString::number(1.0f / yselect, 'f', 8)); 01389 string.replace("%9", QString::number(maxheight, 'f', 8)); 01390 01391 string.replace("COLOUR_UNIFORM", COLOUR_UNIFORM); 01392 } 01393 01394 static const QString YUV2RGBVertexShader = 01395 "GLSL_DEFINES" 01396 "attribute vec2 a_position;\n" 01397 "attribute vec2 a_texcoord0;\n" 01398 "varying vec2 v_texcoord0;\n" 01399 "uniform mat4 u_projection;\n" 01400 "void main() {\n" 01401 " gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\n" 01402 " v_texcoord0 = a_texcoord0;\n" 01403 "}\n"; 01404 01405 static const QString SelectColumn = 01406 " if (fract(v_texcoord0.x * %8) < 0.5)\n" 01407 " yuva = yuva.rabg;\n"; 01408 01409 static const QString YUV2RGBFragmentShader = 01410 "GLSL_DEFINES" 01411 "uniform GLSL_SAMPLER s_texture0;\n" 01412 "uniform mat4 COLOUR_UNIFORM;\n" 01413 "varying vec2 v_texcoord0;\n" 01414 "void main(void)\n" 01415 "{\n" 01416 " vec4 yuva = GLSL_TEXTURE(s_texture0, v_texcoord0);\n" 01417 "SELECT_COLUMN" 01418 " gl_FragColor = vec4(yuva.arb, 1.0) * COLOUR_UNIFORM;\n" 01419 "}\n"; 01420 01421 static const QString OneFieldShader[2] = { 01422 "GLSL_DEFINES" 01423 "uniform GLSL_SAMPLER s_texture0;\n" 01424 "uniform mat4 COLOUR_UNIFORM;\n" 01425 "varying vec2 v_texcoord0;\n" 01426 "void main(void)\n" 01427 "{\n" 01428 " float field = v_texcoord0.y + (step(0.5, fract(v_texcoord0.y * %2)) * %3);\n" 01429 " field = clamp(field, 0.0, %9);\n" 01430 " vec4 yuva = GLSL_TEXTURE(s_texture0, vec2(v_texcoord0.x, field));\n" 01431 "SELECT_COLUMN" 01432 " gl_FragColor = vec4(yuva.arb, 1.0) * COLOUR_UNIFORM;\n" 01433 "}\n", 01434 01435 "GLSL_DEFINES" 01436 "uniform GLSL_SAMPLER s_texture0;\n" 01437 "uniform mat4 COLOUR_UNIFORM;\n" 01438 "varying vec2 v_texcoord0;\n" 01439 "void main(void)\n" 01440 "{\n" 01441 " vec2 field = vec2(0.0, step(0.5, 1.0 - fract(v_texcoord0.y * %2)) * %3);\n" 01442 " vec4 yuva = GLSL_TEXTURE(s_texture0, v_texcoord0 + field);\n" 01443 "SELECT_COLUMN" 01444 " gl_FragColor = vec4(yuva.arb, 1.0) * COLOUR_UNIFORM;\n" 01445 "}\n" 01446 }; 01447 01448 static const QString LinearBlendShader[2] = { 01449 "GLSL_DEFINES" 01450 "uniform GLSL_SAMPLER s_texture0;\n" 01451 "uniform mat4 COLOUR_UNIFORM;\n" 01452 "varying vec2 v_texcoord0;\n" 01453 "void main(void)\n" 01454 "{\n" 01455 " vec2 line = vec2(0.0, %3);\n" 01456 " vec2 line2 = vec2(v_texcoord0.x, clamp(v_texcoord0.y + %3, 0.0, %9));\n" 01457 " vec4 yuva = GLSL_TEXTURE(s_texture0, v_texcoord0);\n" 01458 " vec4 above = GLSL_TEXTURE(s_texture0, line2);\n" 01459 " vec4 below = GLSL_TEXTURE(s_texture0, v_texcoord0 - line);\n" 01460 " if (fract(v_texcoord0.y * %2) >= 0.5)\n" 01461 " yuva = mix(above, below, 0.5);\n" 01462 "SELECT_COLUMN" 01463 " gl_FragColor = vec4(yuva.arb, 1.0) * COLOUR_UNIFORM;\n" 01464 "}\n", 01465 01466 "GLSL_DEFINES" 01467 "uniform GLSL_SAMPLER s_texture0;\n" 01468 "uniform mat4 COLOUR_UNIFORM;\n" 01469 "varying vec2 v_texcoord0;\n" 01470 "void main(void)\n" 01471 "{\n" 01472 " vec2 line = vec2(0.0, %3);\n" 01473 " vec4 yuva = GLSL_TEXTURE(s_texture0, v_texcoord0);\n" 01474 " vec4 above = GLSL_TEXTURE(s_texture0, v_texcoord0 + line);\n" 01475 " vec4 below = GLSL_TEXTURE(s_texture0, v_texcoord0 - line);\n" 01476 " if (fract(v_texcoord0.y * %2) < 0.5)\n" 01477 " yuva = mix(above, below, 0.5);\n" 01478 "SELECT_COLUMN" 01479 " gl_FragColor = vec4(yuva.arb, 1.0) * COLOUR_UNIFORM;\n" 01480 "}\n" 01481 }; 01482 01483 static const QString KernelShader[2] = { 01484 "GLSL_DEFINES" 01485 "uniform GLSL_SAMPLER s_texture1;\n" 01486 "uniform GLSL_SAMPLER s_texture2;\n" 01487 "uniform mat4 COLOUR_UNIFORM;\n" 01488 "varying vec2 v_texcoord0;\n" 01489 "void main(void)\n" 01490 "{\n" 01491 " vec4 yuva = GLSL_TEXTURE(s_texture1, v_texcoord0);\n" 01492 " if (fract(v_texcoord0.y * %2) >= 0.5)\n" 01493 " {\n" 01494 " vec2 twoup = v_texcoord0 - vec2(0.0, %4);\n" 01495 " vec2 twodown = v_texcoord0 + vec2(0.0, %4);\n" 01496 " vec2 onedown = vec2(v_texcoord0.x, clamp(v_texcoord0.y + %3, 0.0, %9));\n" 01497 " vec4 line0 = GLSL_TEXTURE(s_texture1, twoup);\n" 01498 " vec4 line1 = GLSL_TEXTURE(s_texture1, v_texcoord0 - vec2(0.0, %3));\n" 01499 " vec4 line3 = GLSL_TEXTURE(s_texture1, onedown);\n" 01500 " vec4 line4 = GLSL_TEXTURE(s_texture1, twodown);\n" 01501 " vec4 line00 = GLSL_TEXTURE(s_texture2, twoup);\n" 01502 " vec4 line20 = GLSL_TEXTURE(s_texture2, v_texcoord0);\n" 01503 " vec4 line40 = GLSL_TEXTURE(s_texture2, twodown);\n" 01504 " yuva = (yuva * 0.125);\n" 01505 " yuva = (line20 * 0.125) + yuva;\n" 01506 " yuva = (line1 * 0.5) + yuva;\n" 01507 " yuva = (line3 * 0.5) + yuva;\n" 01508 " yuva = (line0 * -0.0625) + yuva;\n" 01509 " yuva = (line4 * -0.0625) + yuva;\n" 01510 " yuva = (line00 * -0.0625) + yuva;\n" 01511 " yuva = (line40 * -0.0625) + yuva;\n" 01512 " }\n" 01513 "SELECT_COLUMN" 01514 " gl_FragColor = vec4(yuva.arb, 1.0) * COLOUR_UNIFORM;\n" 01515 "}\n", 01516 01517 "GLSL_DEFINES" 01518 "uniform GLSL_SAMPLER s_texture0;\n" 01519 "uniform GLSL_SAMPLER s_texture1;\n" 01520 "uniform mat4 COLOUR_UNIFORM;\n" 01521 "varying vec2 v_texcoord0;\n" 01522 "void main(void)\n" 01523 "{\n" 01524 " vec4 yuva = GLSL_TEXTURE(s_texture1, v_texcoord0);\n" 01525 " if (fract(v_texcoord0.y * %2) < 0.5)\n" 01526 " {\n" 01527 " vec2 twoup = v_texcoord0 - vec2(0.0, %4);\n" 01528 " vec2 twodown = v_texcoord0 + vec2(0.0, %4);\n" 01529 " vec4 line0 = GLSL_TEXTURE(s_texture1, twoup);\n" 01530 " vec4 line1 = GLSL_TEXTURE(s_texture1, v_texcoord0 - vec2(0.0, %3));\n" 01531 " vec4 line3 = GLSL_TEXTURE(s_texture1, v_texcoord0 + vec2(0.0, %3));\n" 01532 " vec4 line4 = GLSL_TEXTURE(s_texture1, twodown);\n" 01533 " vec4 line00 = GLSL_TEXTURE(s_texture0, twoup);\n" 01534 " vec4 line20 = GLSL_TEXTURE(s_texture0, v_texcoord0);\n" 01535 " vec4 line40 = GLSL_TEXTURE(s_texture0, twodown);\n" 01536 " yuva = (yuva * 0.125);\n" 01537 " yuva = (line20 * 0.125) + yuva;\n" 01538 " yuva = (line1 * 0.5) + yuva;\n" 01539 " yuva = (line3 * 0.5) + yuva;\n" 01540 " yuva = (line0 * -0.0625) + yuva;\n" 01541 " yuva = (line4 * -0.0625) + yuva;\n" 01542 " yuva = (line00 * -0.0625) + yuva;\n" 01543 " yuva = (line40 * -0.0625) + yuva;\n" 01544 " }\n" 01545 "SELECT_COLUMN" 01546 " gl_FragColor = vec4(yuva.arb, 1.0) * COLOUR_UNIFORM;\n" 01547 "}\n" 01548 }; 01549 01550 static const QString BicubicShader = 01551 "GLSL_DEFINES" 01552 "uniform sampler2D s_texture0;\n" 01553 "uniform sampler1D s_texture1;\n" 01554 "varying vec2 v_texcoord0;\n" 01555 "void main(void)\n" 01556 "{\n" 01557 " vec2 coord = (v_texcoord0 * vec2(%6, %7)) - vec2(0.5, 0.5);\n" 01558 " vec4 parmx = texture1D(s_texture1, coord.x);\n" 01559 " vec4 parmy = texture1D(s_texture1, coord.y);\n" 01560 " vec2 e_x = vec2(%5, 0.0);\n" 01561 " vec2 e_y = vec2(0.0, %3);\n" 01562 " vec2 coord10 = v_texcoord0 + parmx.x * e_x;\n" 01563 " vec2 coord00 = v_texcoord0 - parmx.y * e_x;\n" 01564 " vec2 coord11 = coord10 + parmy.x * e_y;\n" 01565 " vec2 coord01 = coord00 + parmy.x * e_y;\n" 01566 " coord10 = coord10 - parmy.y * e_y;\n" 01567 " coord00 = coord00 - parmy.y * e_y;\n" 01568 " vec4 tex00 = texture2D(s_texture0, coord00);\n" 01569 " vec4 tex10 = texture2D(s_texture0, coord10);\n" 01570 " vec4 tex01 = texture2D(s_texture0, coord01);\n" 01571 " vec4 tex11 = texture2D(s_texture0, coord11);\n" 01572 " tex00 = mix(tex00, tex01, parmy.z);\n" 01573 " tex10 = mix(tex10, tex11, parmy.z);\n" 01574 " gl_FragColor = mix(tex00, tex10, parmx.z);\n" 01575 "}\n"; 01576 01577 void OpenGLVideo::GetProgramStrings(QString &vertex, QString &fragment, 01578 OpenGLFilterType filter, 01579 QString deint, FrameScanType field) 01580 { 01581 uint bottom = field == kScan_Intr2ndField; 01582 vertex = YUV2RGBVertexShader; 01583 switch (filter) 01584 { 01585 case kGLFilterYUV2RGB: 01586 { 01587 if (deint == "openglonefield" || deint == "openglbobdeint") 01588 fragment = OneFieldShader[bottom]; 01589 else if (deint == "opengllinearblend" || 01590 deint == "opengldoubleratelinearblend") 01591 fragment = LinearBlendShader[bottom]; 01592 else if (deint == "openglkerneldeint" || 01593 deint == "opengldoubleratekerneldeint") 01594 fragment = KernelShader[bottom]; 01595 else 01596 fragment = YUV2RGBFragmentShader; 01597 01598 fragment.replace("SELECT_COLUMN", MYTHTV_UYVY == videoTextureType ? 01599 SelectColumn : ""); 01600 break; 01601 } 01602 case kGLFilterNone: 01603 case kGLFilterResize: 01604 break; 01605 case kGLFilterBicubic: 01606 fragment = BicubicShader; 01607 break; 01608 default: 01609 LOG(VB_PLAYBACK, LOG_ERR, LOC + "Unknown filter"); 01610 break; 01611 } 01612 CustomiseProgramString(vertex); 01613 CustomiseProgramString(fragment); 01614 }
1.7.6.1