00001
00002 #include "mythcontext.h"
00003 #include "tv.h"
00004 #include "openglvideo.h"
00005 #include "openglcontext.h"
00006
00007
00008 extern "C" {
00009 #include "../libavcodec/avcodec.h"
00010 }
00011
00012
00013 #define GL_GLEXT_PROTOTYPES
00014 #define GLX_GLXEXT_PROTOTYPES
00015 #define XMD_H 1
00016
00017 #include <GL/gl.h>
00018 #undef GLX_ARB_get_proc_address
00019
00020
00021 #include "util-opengl.h"
00022
00023 #define LOC QString("GLVid: ")
00024 #define LOC_ERR QString("GLVid, Error: ")
00025
00026 class OpenGLFilter
00027 {
00028 public:
00029 GLuint fragmentProgram;
00030 uint numInputs;
00031 bool rotateFrameBuffers;
00032 vector<GLuint> frameBuffers;
00033 vector<GLuint> frameBufferTextures;
00034 DisplayBuffer outputBuffer;
00035 };
00036
00037 OpenGLVideo::OpenGLVideo() :
00038 gl_context(NULL), videoSize(0,0),
00039 viewportSize(0,0), masterViewportSize(0,0),
00040 visibleRect(0,0,0,0), videoRect(0,0,0,0),
00041 frameRect(0,0,0,0),
00042 frameBufferRect(0,0,0,0), invertVideo(false),
00043 softwareDeinterlacer(QString::null),
00044 hardwareDeinterlacing(false),
00045 useColourControl(false), viewportControl(false),
00046 frameBuffer(0), frameBufferTexture(0),
00047 inputTextureSize(0,0), currentFrameNum(0),
00048 inputUpdated(false),
00049
00050 convertSize(0,0), convertBuf(NULL),
00051
00052 videoResize(false), videoResizeRect(0,0,0,0)
00053 {
00054 }
00055
00056 OpenGLVideo::~OpenGLVideo()
00057 {
00058 Teardown();
00059 }
00060
00061
00062 void OpenGLVideo::Teardown(void)
00063 {
00064 ShutDownYUV2RGB();
00065
00066 gl_context->MakeCurrent(true);
00067
00068 if (frameBuffer)
00069 gl_context->DeleteFrameBuffer(frameBuffer);
00070
00071 if (frameBufferTexture)
00072 gl_context->DeleteTexture(frameBufferTexture);
00073
00074 for (uint i = 0; i < inputTextures.size(); i++)
00075 gl_context->DeleteTexture(inputTextures[i]);
00076 inputTextures.clear();
00077
00078 if (!filters.empty())
00079 {
00080 glfilt_map_t::iterator it;
00081 for (it = filters.begin(); it != filters.end(); ++it)
00082 {
00083 if (it->second->fragmentProgram)
00084 gl_context->DeleteFragmentProgram(it->second->fragmentProgram);
00085 vector<GLuint> temp = it->second->frameBuffers;
00086 for (uint i = 0; i < temp.size(); i++)
00087 gl_context->DeleteFrameBuffer(temp[i]);
00088 temp = it->second->frameBufferTextures;
00089 for (uint i = 0; i < temp.size(); i++)
00090 gl_context->DeleteTexture((temp[i]));
00091 }
00092 }
00093 filters.clear();
00094
00095 gl_context->MakeCurrent(false);
00096 }
00097
00098
00099 bool OpenGLVideo::Init(OpenGLContext *glcontext, bool colour_control,
00100 bool onscreen, QSize video_size, QRect visible_rect,
00101 QRect video_rect, QRect frame_rect,
00102 bool viewport_control, bool osd)
00103 {
00104 gl_context = glcontext;
00105 videoSize = video_size;
00106 visibleRect = visible_rect;
00107 videoRect = video_rect;
00108 frameRect = frame_rect;
00109 masterViewportSize = QSize(1920, 1080);
00110
00111 QSize rect = GetTextureSize(videoSize);
00112
00113 frameBufferRect = QRect(QPoint(0,0), rect);
00114 invertVideo = true;
00115 softwareDeinterlacer = "";
00116 hardwareDeinterlacing = false;
00117 useColourControl = colour_control;
00118 viewportControl = viewport_control;
00119 inputTextureSize = QSize(0,0);
00120 convertSize = QSize(0,0);
00121 videoResize = false;
00122 videoResizeRect = QRect(0,0,0,0);
00123 frameBuffer = 0;
00124 currentFrameNum = -1;
00125 inputUpdated = false;
00126
00127 if (!onscreen)
00128 {
00129 QSize fb_size = GetTextureSize(visibleRect.size());
00130 if (!AddFrameBuffer(frameBuffer, frameBufferTexture, fb_size))
00131 return false;
00132 }
00133
00134 SetViewPort(visibleRect.size());
00135 InitOpenGL();
00136
00137 if (osd)
00138 {
00139 QSize osdsize = visibleRect.size();
00140 QSize half_size(osdsize.width() >> 1, osdsize.height() >>1);
00141 GLuint alphatex = CreateVideoTexture(osdsize, inputTextureSize);
00142 GLuint utex = CreateVideoTexture(half_size, inputTextureSize);
00143 GLuint vtex = CreateVideoTexture(half_size, inputTextureSize);
00144 GLuint ytex = CreateVideoTexture(osdsize, inputTextureSize);
00145
00146 if ((alphatex && ytex && utex && vtex) && AddFilter(kGLFilterYUV2RGBA))
00147 {
00148 inputTextures.push_back(ytex);
00149 inputTextures.push_back(utex);
00150 inputTextures.push_back(vtex);
00151 inputTextures.push_back(alphatex);
00152 if (!AddFilter(kGLFilterResize))
00153 {
00154 Teardown();
00155 return false;
00156 }
00157 }
00158 }
00159 else
00160 {
00161 QSize half_size(videoSize.width() >> 1, videoSize.height() >>1);
00162 GLuint utex = CreateVideoTexture(half_size, inputTextureSize);
00163 GLuint vtex = CreateVideoTexture(half_size, inputTextureSize);
00164 GLuint ytex = CreateVideoTexture(videoSize, inputTextureSize);;
00165
00166 if ((ytex && utex && vtex) && AddFilter(kGLFilterYUV2RGB))
00167 {
00168 inputTextures.push_back(ytex);
00169 inputTextures.push_back(utex);
00170 inputTextures.push_back(vtex);
00171 }
00172 }
00173
00174 if (filters.empty())
00175 {
00176 if (osd)
00177 {
00178 Teardown();
00179 return false;
00180 }
00181
00182 VERBOSE(VB_PLAYBACK, LOC +
00183 "OpenGL colour conversion failed.\n\t\t\t"
00184 "Falling back to software conversion.\n\t\t\t"
00185 "Any opengl filters will also be disabled.");
00186
00187 GLuint rgb24tex = CreateVideoTexture(videoSize, inputTextureSize);
00188
00189 if (rgb24tex && AddFilter(kGLFilterResize))
00190 {
00191 inputTextures.push_back(rgb24tex);
00192 }
00193 else
00194 {
00195 VERBOSE(VB_IMPORTANT, LOC_ERR + "Fatal error");
00196 Teardown();
00197 return false;
00198 }
00199 }
00200
00201 return true;
00202 }
00203
00204 OpenGLFilterType OpenGLVideo::GetDeintFilter(void) const
00205 {
00206 if (filters.count(kGLFilterKernelDeint))
00207 return kGLFilterKernelDeint;
00208 if (filters.count(kGLFilterLinearBlendDeint))
00209 return kGLFilterLinearBlendDeint;
00210 if (filters.count(kGLFilterOneFieldDeint))
00211 return kGLFilterOneFieldDeint;
00212 if (filters.count(kGLFilterBobDeintDFR))
00213 return kGLFilterBobDeintDFR;
00214 if (filters.count(kGLFilterOneFieldDeintDFR))
00215 return kGLFilterOneFieldDeintDFR;
00216 if (filters.count(kGLFilterLinearBlendDeintDFR))
00217 return kGLFilterLinearBlendDeintDFR;
00218 if (filters.count(kGLFilterKernelDeintDFR))
00219 return kGLFilterKernelDeintDFR;
00220 if (filters.count(kGLFilterFieldOrderDFR))
00221 return kGLFilterFieldOrderDFR;
00222
00223 return kGLFilterNone;
00224 }
00225
00226 bool OpenGLVideo::OptimiseFilters(void)
00227 {
00228
00229
00230
00231
00232
00233 bool needResize = ((videoSize.height() != videoRect.height()) ||
00234 (videoSize.width() < videoRect.width()));
00235 if (needResize && !filters.count(kGLFilterResize) &&
00236 !(AddFilter(kGLFilterResize)))
00237 {
00238 return false;
00239 }
00240
00241 glfilt_map_t::reverse_iterator it;
00242
00243
00244
00245 uint buffers_needed = 1;
00246 bool last_filter = true;
00247 bool needtorotate = false;
00248 for (it = filters.rbegin(); it != filters.rend(); it++)
00249 {
00250 it->second->outputBuffer = kFrameBufferObject;
00251 it->second->rotateFrameBuffers = needtorotate;
00252 if (!last_filter)
00253 {
00254 uint buffers_have = it->second->frameBuffers.size();
00255 int buffers_diff = buffers_needed - buffers_have;
00256 if (buffers_diff > 0)
00257 {
00258 uint tmp_buf, tmp_tex;
00259 QSize fb_size = GetTextureSize(videoSize);
00260 for (int i = 0; i < buffers_diff; i++)
00261 {
00262 if (!AddFrameBuffer(tmp_buf, tmp_tex, fb_size))
00263 return false;
00264 else
00265 {
00266 it->second->frameBuffers.push_back(tmp_buf);
00267 it->second->frameBufferTextures.push_back(tmp_tex);
00268 }
00269 }
00270 }
00271 else if (buffers_diff < 0)
00272 {
00273 for (int i = 0; i > buffers_diff; i--)
00274 {
00275 OpenGLFilter *filt = it->second;
00276
00277 gl_context->DeleteFrameBuffer(
00278 filt->frameBuffers.back());
00279 gl_context->DeleteTexture(
00280 filt->frameBufferTextures.back());
00281
00282 filt->frameBuffers.pop_back();
00283 filt->frameBufferTextures.pop_back();
00284 }
00285 }
00286 }
00287 else
00288 {
00289 last_filter = false;
00290 }
00291
00292 buffers_needed = it->second->numInputs;
00293 needtorotate = (it->first == kGLFilterKernelDeint ||
00294 it->first == kGLFilterLinearBlendDeint ||
00295 it->first == kGLFilterOneFieldDeintDFR ||
00296 it->first == kGLFilterLinearBlendDeintDFR ||
00297 it->first == kGLFilterKernelDeintDFR ||
00298 it->first == kGLFilterFieldOrderDFR);
00299
00300 }
00301
00302 bool deinterlacing = hardwareDeinterlacing;
00303 hardwareDeinterlacing = true;
00304
00305 SetDeinterlacing(false);
00306 if (deinterlacing)
00307 SetDeinterlacing(deinterlacing);
00308
00309 return true;
00310 }
00311
00312
00313 void OpenGLVideo::SetFiltering(void)
00314 {
00315
00316
00317 if (filters.empty())
00318 return;
00319
00320 if (filters.size() == 1)
00321 {
00322 SetTextureFilters(&inputTextures, GL_LINEAR);
00323 return;
00324 }
00325
00326 SetTextureFilters(&inputTextures, GL_NEAREST);
00327 vector<GLuint> textures;
00328 glfilt_map_t::iterator it;
00329 for (it = filters.begin(); it != filters.end(); it++)
00330 SetTextureFilters(&(it->second->frameBufferTextures), GL_NEAREST);
00331
00332
00333 glfilt_map_t::reverse_iterator rit;
00334 bool next = false;
00335 bool resize = filters.count(kGLFilterResize);
00336 for (rit = filters.rbegin(); rit != filters.rend(); rit++)
00337 {
00338 if (next && (rit->second->outputBuffer != kNoBuffer))
00339 {
00340 SetTextureFilters(&(rit->second->frameBufferTextures), GL_LINEAR);
00341 return;
00342 }
00343
00344 if (resize)
00345 {
00346 next |= ((rit->first == kGLFilterResize) ||
00347 (rit->second->outputBuffer == kDefaultBuffer));
00348 }
00349 }
00350
00351 SetTextureFilters(&inputTextures, GL_LINEAR);
00352 }
00353
00354
00355 bool OpenGLVideo::ReInit(OpenGLContext *glcontext, bool colour_control,
00356 bool onscreen, QSize video_size, QRect visible_rect,
00357 QRect video_rect, QRect frame_rect,
00358 bool viewport_control, bool osd)
00359 {
00360 VERBOSE(VB_PLAYBACK, LOC + "Reinit");
00361
00362 gl_context->MakeCurrent(true);
00363
00364 QString harddeint = GetDeinterlacer();
00365 QString softdeint = softwareDeinterlacer;
00366 bool interlacing = hardwareDeinterlacing;
00367 bool resize = videoResize;
00368 QRect resize_rect = videoResizeRect;
00369
00370 Teardown();
00371
00372 bool success = Init(glcontext, colour_control, onscreen, video_size,
00373 visible_rect, video_rect, frame_rect,
00374 viewport_control, osd);
00375
00376 if (harddeint != "")
00377 success &= AddDeinterlacer(harddeint);
00378
00379 softwareDeinterlacer = softdeint;
00380 SetDeinterlacing(interlacing);
00381
00382 if (resize)
00383 SetVideoResize(resize_rect);
00384
00385 return success;
00386 }
00387
00388
00389 bool OpenGLVideo::AddFilter(OpenGLFilterType filter)
00390 {
00391 if (filters.count(filter))
00392 return true;
00393
00394 VERBOSE(VB_PLAYBACK, LOC + QString("Creating %1 filter.")
00395 .arg(FilterToString(filter)));
00396
00397 gl_context->MakeCurrent(true);
00398
00399 OpenGLFilter *temp = new OpenGLFilter();
00400
00401 temp->numInputs = 1;
00402
00403 if ((filter == kGLFilterLinearBlendDeint) ||
00404 (filter == kGLFilterKernelDeint) ||
00405 (filter == kGLFilterFieldOrderDFR))
00406 {
00407 temp->numInputs = 2;
00408 }
00409 else if ((filter == kGLFilterYUV2RGB) ||
00410 (filter == kGLFilterOneFieldDeintDFR) ||
00411 (filter == kGLFilterKernelDeintDFR) ||
00412 (filter == kGLFilterLinearBlendDeintDFR))
00413 {
00414 temp->numInputs = 3;
00415 }
00416 else if ((filter == kGLFilterYUV2RGBA))
00417 {
00418 temp->numInputs = 4;
00419 }
00420
00421 GLuint program = 0;
00422 if (filter != kGLFilterNone && filter != kGLFilterResize)
00423 {
00424 program = AddFragmentProgram(filter);
00425 if (!program)
00426 return false;
00427 }
00428
00429 temp->fragmentProgram = program;
00430 temp->outputBuffer = kDefaultBuffer;
00431 temp->rotateFrameBuffers = false;
00432
00433 temp->frameBuffers.clear();
00434 temp->frameBufferTextures.clear();
00435
00436 filters[filter] = temp;
00437
00438 if (OptimiseFilters())
00439 return true;
00440
00441 RemoveFilter(filter);
00442
00443 return false;
00444 }
00445
00446
00447 bool OpenGLVideo::RemoveFilter(OpenGLFilterType filter)
00448 {
00449 if (!filters.count(filter))
00450 return true;
00451
00452 VERBOSE(VB_PLAYBACK, QString("Removing %1 filter")
00453 .arg(FilterToString(filter)));
00454
00455 gl_context->MakeCurrent(true);
00456
00457 gl_context->DeleteFragmentProgram(filters[filter]->fragmentProgram);
00458
00459 vector<GLuint> temp;
00460 vector<GLuint>::iterator it;
00461
00462 temp = filters[filter]->frameBuffers;
00463 for (it = temp.begin(); it != temp.end(); it++)
00464 gl_context->DeleteFrameBuffer(*it);
00465
00466 temp = filters[filter]->frameBufferTextures;
00467 for (it = temp.begin(); it != temp.end(); it++)
00468 gl_context->DeleteTexture((*(it)));
00469
00470 filters.erase(filter);
00471
00472 gl_context->MakeCurrent(false);
00473
00474 return true;
00475 }
00476
00477
00478 bool OpenGLVideo::AddDeinterlacer(const QString &filter)
00479 {
00480 QString current_deinterlacer = GetDeinterlacer();
00481
00482 if (current_deinterlacer == filter)
00483 return true;
00484
00485 if (!current_deinterlacer.isEmpty())
00486 RemoveFilter(current_deinterlacer);
00487
00488 return AddFilter(filter);
00489 }
00490
00491
00492 uint OpenGLVideo::AddFragmentProgram(OpenGLFilterType name)
00493 {
00494 if (!gl_context->IsFeatureSupported(kGLExtFragProg))
00495 {
00496 VERBOSE(VB_PLAYBACK, LOC_ERR + "Fragment programs not supported");
00497 return 0;
00498 }
00499
00500 QString program = GetProgramString(name);
00501 QString texType = (gl_context->IsFeatureSupported(kGLExtRect)) ? "RECT" : "2D";
00502 program.replace("%1", texType);
00503
00504 uint ret;
00505 if (gl_context->CreateFragmentProgram(program, ret))
00506 {
00507 VERBOSE(VB_PLAYBACK, LOC + QString("Created fragment program %1.")
00508 .arg(FilterToString(name)));
00509
00510 return ret;
00511 }
00512
00513 return 0;
00514 }
00515
00516
00517 bool OpenGLVideo::AddFrameBuffer(uint &framebuffer,
00518 uint &texture, QSize size)
00519 {
00520 if (!gl_context->IsFeatureSupported(kGLExtFBufObj))
00521 {
00522 VERBOSE(VB_PLAYBACK, LOC_ERR + "Framebuffer binding not supported.");
00523 return false;
00524 }
00525
00526 texture = gl_context->CreateTexture();
00527
00528 bool ok = gl_context->CreateFrameBuffer(framebuffer, texture, size);
00529
00530 if (!ok)
00531 gl_context->DeleteTexture(texture);
00532
00533 return ok;
00534 }
00535
00536
00537 void OpenGLVideo::SetViewPort(const QSize &viewPortSize)
00538 {
00539 uint w = max(viewPortSize.width(), videoSize.width());
00540 uint h = max(viewPortSize.height(), videoSize.height());
00541
00542 viewportSize = QSize(w, h);
00543
00544 if (!viewportControl)
00545 return;
00546
00547 VERBOSE(VB_PLAYBACK, LOC + QString("Viewport: %1x%2")
00548 .arg(w).arg(h));
00549
00550 SetViewPortPrivate(viewportSize);
00551 }
00552
00553 void OpenGLVideo::SetViewPortPrivate(const QSize &viewPortSize)
00554 {
00555 glViewport(0, 0, viewPortSize.width(), viewPortSize.height());
00556 glMatrixMode(GL_PROJECTION);
00557 glLoadIdentity();
00558 glOrtho(0, viewPortSize.width() - 1,
00559 0, viewPortSize.height() - 1, 1, -1);
00560 glMatrixMode(GL_MODELVIEW);
00561 glLoadIdentity();
00562 }
00563
00564
00565 void OpenGLVideo::InitOpenGL(void)
00566 {
00567 gl_context->MakeCurrent(true);
00568 glDisable(GL_BLEND);
00569 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00570 glDisable(GL_DEPTH_TEST);
00571 glDepthMask(GL_FALSE);
00572 glDisable(GL_CULL_FACE);
00573 gl_context->EnableTextures();;
00574 glShadeModel(GL_FLAT);
00575 glDisable(GL_POLYGON_SMOOTH);
00576 glDisable(GL_LINE_SMOOTH);
00577 glDisable(GL_POINT_SMOOTH);
00578 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
00579 glClear(GL_COLOR_BUFFER_BIT);
00580 glFlush();
00581 gl_context->MakeCurrent(false);
00582 }
00583
00584
00585 uint OpenGLVideo::CreateVideoTexture(QSize size, QSize &tex_size)
00586 {
00587 uint tmp_tex = gl_context->CreateTexture();
00588
00589 QSize temp = GetTextureSize(size);
00590
00591 if ((temp.width() > (int)gl_context->GetMaxTexSize()) ||
00592 (temp.height() > (int)gl_context->GetMaxTexSize()) ||
00593 !gl_context->SetupTexture(temp, tmp_tex, GL_LINEAR))
00594 {
00595 VERBOSE(VB_PLAYBACK, LOC_ERR + "Could not create texture.");
00596 gl_context->DeleteTexture(tmp_tex);
00597 return 0;
00598 }
00599
00600 tex_size = temp;
00601
00602 VERBOSE(VB_PLAYBACK, LOC + QString("Created main input texture %1x%2")
00603 .arg(temp.width()).arg(temp.height()));
00604
00605 return tmp_tex;
00606 }
00607
00608
00609 QSize OpenGLVideo::GetTextureSize(const QSize &size)
00610 {
00611 if (gl_context->IsFeatureSupported(kGLExtRect))
00612 return size;
00613
00614 int w = 64;
00615 int h = 64;
00616
00617 while (w < size.width())
00618 {
00619 w *= 2;
00620 }
00621
00622 while (h < size.height())
00623 {
00624 h *= 2;
00625 }
00626
00627 return QSize(w, h);
00628 }
00629
00630
00631 void OpenGLVideo::UpdateInputFrame(const VideoFrame *frame)
00632 {
00633 if (frame->width != videoSize.width() ||
00634 frame->height != videoSize.height() ||
00635 frame->width < 1 ||
00636 frame->height < 1)
00637 {
00638 ShutDownYUV2RGB();
00639 return;
00640 }
00641
00642 if (filters.count(kGLFilterYUV2RGB) && (frame->codec == FMT_YV12))
00643 {
00644 UpdateInput(frame->buf, frame->offsets, 0, FMT_YV12, videoSize);
00645 return;
00646 }
00647
00648
00649 if (convertSize != videoSize)
00650 {
00651 ShutDownYUV2RGB();
00652
00653 VERBOSE(VB_PLAYBACK, LOC + "Init software conversion.");
00654
00655 convertSize = videoSize;
00656 convertBuf = new unsigned char[
00657 (videoSize.width() * videoSize.height() * 3) + 128];
00658 }
00659
00660 if (convertBuf)
00661 {
00662 AVPicture img_in, img_out;
00663
00664 avpicture_fill(&img_out, (uint8_t *)convertBuf, PIX_FMT_RGB24,
00665 convertSize.width(), convertSize.height());
00666 avpicture_fill(&img_in, (uint8_t *)frame->buf, PIX_FMT_YUV420P,
00667 convertSize.width(), convertSize.height());
00668 img_convert(&img_out, PIX_FMT_RGB24,
00669 &img_in, PIX_FMT_YUV420P,
00670 convertSize.width(), convertSize.height());
00671
00672 int offset = 0;
00673 UpdateInput(convertBuf, &offset, 0, FMT_RGB24, convertSize);
00674 }
00675 }
00676
00677
00678 void OpenGLVideo::UpdateInput(const unsigned char *buf, const int *offsets,
00679 uint texture_index, int format, QSize size)
00680 {
00681 inputUpdated = false;
00682
00683 if (texture_index >= inputTextures.size())
00684 return;
00685
00686 copy_pixels_to_texture(
00687 buf + offsets[0], format, size,
00688 inputTextures[texture_index], gl_context->GetTextureType());
00689
00690 if (FMT_YV12 == format)
00691 {
00692 QSize chroma_size(size.width() >> 1, size.height() >> 1);
00693 copy_pixels_to_texture(
00694 buf + offsets[1], format, chroma_size,
00695 inputTextures[texture_index + 1],
00696 gl_context->GetTextureType());
00697 copy_pixels_to_texture(
00698 buf + offsets[2], format, chroma_size,
00699 inputTextures[texture_index + 2],
00700 gl_context->GetTextureType());
00701 }
00702
00703 inputUpdated = true;
00704 }
00705
00706
00707 void OpenGLVideo::ShutDownYUV2RGB(void)
00708 {
00709 if (convertBuf)
00710 {
00711 delete convertBuf;
00712 convertBuf = NULL;
00713 }
00714 convertSize = QSize(0,0);
00715 }
00716
00717
00718
00719 void OpenGLVideo::SetVideoResize(const QRect &rect)
00720 {
00721 bool abort = ((rect.right() > videoSize.width()) ||
00722 (rect.bottom() > videoSize.height()) ||
00723 (rect.width() > videoSize.width()) ||
00724 (rect.height() > videoSize.height()));
00725
00726
00727
00728 abort |= !rect.left() && !rect.top() && (rect.size() == videoSize);
00729
00730 if (!abort)
00731 {
00732 videoResize = true;
00733 videoResizeRect = rect;
00734 return;
00735 }
00736
00737 DisableVideoResize();
00738 }
00739
00740
00741 void OpenGLVideo::DisableVideoResize(void)
00742 {
00743 videoResize = false;
00744 videoResizeRect = QRect(0, 0, 0, 0);
00745 }
00746
00747 void OpenGLVideo::CalculateResize(float &left, float &top,
00748 float &right, float &bottom)
00749 {
00750
00751
00752 if ((videoSize.height() <= 0) || (videoSize.width() <= 0))
00753 return;
00754
00755 float height = visibleRect.height();
00756 float new_top = height - ((float)videoResizeRect.bottom() /
00757 (float)videoSize.height()) * height;
00758 float new_bottom = height - ((float)videoResizeRect.top() /
00759 (float)videoSize.height()) * height;
00760
00761 left = (((float) videoResizeRect.left() / (float) videoSize.width()) *
00762 visibleRect.width());
00763 right = (((float) videoResizeRect.right() / (float) videoSize.width()) *
00764 visibleRect.width());
00765
00766 top = new_top;
00767 bottom = new_bottom;
00768 }
00769
00770
00771 void OpenGLVideo::SetDeinterlacing(bool deinterlacing)
00772 {
00773 if (deinterlacing == hardwareDeinterlacing)
00774 return;
00775
00776 VERBOSE(VB_PLAYBACK, LOC + QString("Turning %1 deinterlacing.")
00777 .arg(deinterlacing ? "on" : "off"));
00778
00779 hardwareDeinterlacing = deinterlacing;
00780
00781 glfilt_map_t::iterator it = filters.begin();
00782 for (; it != filters.end(); it++)
00783 {
00784 it->second->outputBuffer = kFrameBufferObject;
00785
00786 if ((it->first >= kGLFilterLinearBlendDeint) &&
00787 (it->first <= kGLFilterOneFieldDeintDFR) &&
00788 !deinterlacing)
00789 {
00790 it->second->outputBuffer = kNoBuffer;
00791 }
00792 }
00793
00794 glfilt_map_t::reverse_iterator rit = filters.rbegin();
00795 for (; rit != filters.rend(); rit++)
00796 {
00797 if (rit->second->outputBuffer == kFrameBufferObject)
00798 {
00799 rit->second->outputBuffer = kDefaultBuffer;
00800 break;
00801 }
00802 }
00803
00804 gl_context->MakeCurrent(true);
00805 SetFiltering();
00806 gl_context->MakeCurrent(false);
00807 }
00808
00809
00810 void OpenGLVideo::PrepareFrame(FrameScanType scan, bool softwareDeinterlacing,
00811 long long frame)
00812 {
00813 if (inputTextures.empty() || filters.empty())
00814 return;
00815
00816 vector<GLuint> inputs = inputTextures;
00817 QSize inputsize = inputTextureSize;
00818 uint numfilters = filters.size();
00819
00820 glfilt_map_t::iterator it;
00821 for (it = filters.begin(); it != filters.end(); it++)
00822 {
00823 if (it->second->rotateFrameBuffers &&
00824 !(it->first == kGLFilterYUV2RGB && scan == kScan_Intr2ndField))
00825 {
00826 Rotate(&(it->second->frameBufferTextures));
00827 Rotate(&(it->second->frameBuffers));
00828 }
00829
00830
00831 if (it->second->outputBuffer == kNoBuffer)
00832 continue;
00833
00834 OpenGLFilterType type = it->first;
00835 OpenGLFilter *filter = it->second;
00836
00837
00838 if (!inputUpdated && type == kGLFilterYUV2RGBA)
00839 {
00840 inputs = filter->frameBufferTextures;
00841 inputsize = videoSize;
00842 continue;
00843 }
00844
00845
00846 if (!inputUpdated && (frame == currentFrameNum) &&
00847 (type == kGLFilterYUV2RGB) && (frame != 0) &&
00848 (!(softwareDeinterlacing && softwareDeinterlacer == "bobdeint")))
00849 {
00850 inputs = filter->frameBufferTextures;
00851 inputsize = videoSize;
00852 continue;
00853 }
00854
00855
00856 float t_right = (float)videoSize.width();
00857 float t_bottom = (float)videoSize.height();
00858 float t_top = 0.0f;
00859 float t_left = 0.0f;
00860 float trueheight = (float)videoSize.height();
00861
00862
00863 if (filter->outputBuffer == kDefaultBuffer)
00864 {
00865 t_left = (float)frameRect.left();
00866 t_right = (float)frameRect.width() + t_left;
00867 t_top = (float)frameRect.top();
00868 t_bottom = (float)frameRect.height() + t_top;
00869 }
00870
00871 if (!gl_context->IsFeatureSupported(kGLExtRect) &&
00872 (inputsize.width() > 0) && (inputsize.height() > 0))
00873 {
00874 t_right /= inputsize.width();
00875 t_left /= inputsize.width();
00876 t_bottom /= inputsize.height();
00877 t_top /= inputsize.height();
00878 trueheight /= inputsize.height();
00879 }
00880
00881 float line_height = (trueheight / (float)videoSize.height());
00882 float bob = line_height / 2.0f;
00883
00884 if (type == kGLFilterBobDeintDFR)
00885 {
00886 if (scan == kScan_Interlaced)
00887 {
00888 t_bottom += bob;
00889 t_top += bob;
00890 }
00891 if (scan == kScan_Intr2ndField)
00892 {
00893 t_bottom -= bob;
00894 t_top -= bob;
00895 }
00896 }
00897
00898 if (softwareDeinterlacer == "bobdeint" &&
00899 softwareDeinterlacing && (type == kGLFilterYUV2RGB ||
00900 (type == kGLFilterResize && numfilters == 1)))
00901 {
00902 bob = line_height / 4.0f;
00903 if (scan == kScan_Interlaced)
00904 {
00905 t_top /= 2;
00906 t_bottom /= 2;
00907 t_bottom += bob;
00908 t_top += bob;
00909 }
00910 if (scan == kScan_Intr2ndField)
00911 {
00912 t_top = (trueheight / 2) + (t_top / 2);
00913 t_bottom = (trueheight / 2) + (t_bottom / 2);
00914 t_bottom -= bob;
00915 t_top -= bob;
00916 }
00917 }
00918
00919 float t_right_uv = t_right;
00920 float t_top_uv = t_top;
00921 float t_bottom_uv = t_bottom;
00922 float t_left_uv = t_left;
00923
00924 if (gl_context->IsFeatureSupported(kGLExtRect))
00925 {
00926 t_right_uv /= 2;
00927 t_top_uv /= 2;
00928 t_bottom_uv /= 2;
00929 t_left_uv /= 2;
00930 }
00931
00932
00933 QRect display = (filter->frameBuffers.empty() ||
00934 filter->outputBuffer == kDefaultBuffer) ?
00935 videoRect : frameBufferRect;
00936
00937 float vleft = display.left();
00938 float vright = display.right();
00939 float vtop = display.top();
00940 float vbot = display.bottom();
00941
00942
00943 if (videoResize && filter->outputBuffer == kDefaultBuffer)
00944 CalculateResize(vleft, vtop, vright, vbot);
00945
00946 if (invertVideo &&
00947 ((type == kGLFilterYUV2RGB) || (type == kGLFilterYUV2RGBA)) ||
00948 ((type == kGLFilterResize) && (numfilters == 1)))
00949 {
00950 float temp = vtop;
00951 vtop = vbot;
00952 vbot = temp;
00953 }
00954
00955
00956 switch (filter->outputBuffer)
00957 {
00958 case kDefaultBuffer:
00959 if (frameBuffer)
00960 gl_context->BindFramebuffer(frameBuffer);
00961
00962
00963 if (viewportControl)
00964 {
00965 glClear(GL_COLOR_BUFFER_BIT);
00966 SetViewPortPrivate(visibleRect.size());
00967 }
00968 else
00969 {
00970 SetViewPortPrivate(masterViewportSize);
00971 }
00972
00973 break;
00974
00975 case kFrameBufferObject:
00976 if (!filter->frameBuffers.empty())
00977 {
00978 gl_context->BindFramebuffer(filter->frameBuffers[0]);
00979 SetViewPortPrivate(frameBufferRect.size());
00980 }
00981 break;
00982
00983 case kNoBuffer:
00984 continue;
00985 }
00986
00987
00988 for (uint i = 0; i < inputs.size(); i++)
00989 {
00990 glActiveTexture(GL_TEXTURE0 + i);
00991 glBindTexture(gl_context->GetTextureType(), inputs[i]);
00992 }
00993
00994
00995 if ((type != kGLFilterNone) && (type != kGLFilterResize))
00996 {
00997 glEnable(GL_FRAGMENT_PROGRAM_ARB);
00998 gl_context->BindFragmentProgram(filter->fragmentProgram);
00999 float field = -line_height;
01000
01001 switch (type)
01002 {
01003 case kGLFilterYUV2RGB:
01004 case kGLFilterYUV2RGBA:
01005 if (useColourControl)
01006 {
01007 gl_context->InitFragmentParams(
01008 0,
01009 pictureAttribs[kPictureAttribute_Brightness],
01010 pictureAttribs[kPictureAttribute_Contrast],
01011 pictureAttribs[kPictureAttribute_Colour],
01012 0.0f);
01013 }
01014 break;
01015
01016 case kGLFilterBobDeintDFR:
01017 case kGLFilterOneFieldDeintDFR:
01018 case kGLFilterKernelDeintDFR:
01019 case kGLFilterFieldOrderDFR:
01020 case kGLFilterLinearBlendDeintDFR:
01021 if (scan == kScan_Intr2ndField)
01022 field *= -1;
01023
01024 case kGLFilterOneFieldDeint:
01025 case kGLFilterKernelDeint:
01026 case kGLFilterLinearBlendDeint:
01027 gl_context->InitFragmentParams(
01028 0, line_height * 2.0f, field, 0.0f, 0.0f);
01029 break;
01030
01031 case kGLFilterNone:
01032 case kGLFilterResize:
01033 break;
01034 }
01035 }
01036
01037
01038 if (type == kGLFilterResize && filters.count(kGLFilterYUV2RGBA))
01039 glEnable(GL_BLEND);
01040
01041
01042 glBegin(GL_QUADS);
01043 glTexCoord2f(t_left, t_top);
01044 if (type == kGLFilterYUV2RGB || type == kGLFilterYUV2RGBA)
01045 {
01046 glMultiTexCoord2f(GL_TEXTURE1, t_left_uv, t_top_uv);
01047 glMultiTexCoord2f(GL_TEXTURE2, t_left_uv, t_top_uv);
01048 if (type == kGLFilterYUV2RGBA)
01049 glMultiTexCoord2f(GL_TEXTURE3, t_left_uv, t_top_uv);
01050 }
01051 glVertex2f(vleft, vtop);
01052
01053 glTexCoord2f(t_right, t_top);
01054 if (type == kGLFilterYUV2RGB || type == kGLFilterYUV2RGBA)
01055 {
01056 glMultiTexCoord2f(GL_TEXTURE1, t_right_uv, t_top_uv);
01057 glMultiTexCoord2f(GL_TEXTURE2, t_right_uv, t_top_uv);
01058 if (type == kGLFilterYUV2RGBA)
01059 glMultiTexCoord2f(GL_TEXTURE3, t_right, t_top);
01060 }
01061 glVertex2f(vright, vtop);
01062
01063 glTexCoord2f(t_right, t_bottom);
01064 if (type == kGLFilterYUV2RGB || type == kGLFilterYUV2RGBA)
01065 {
01066 glMultiTexCoord2f(GL_TEXTURE1, t_right_uv, t_bottom_uv);
01067 glMultiTexCoord2f(GL_TEXTURE2, t_right_uv, t_bottom_uv);
01068 if (type == kGLFilterYUV2RGBA)
01069 glMultiTexCoord2f(GL_TEXTURE3, t_right, t_bottom);
01070 }
01071 glVertex2f(vright, vbot);
01072
01073 glTexCoord2f(t_left, t_bottom);
01074 if (type == kGLFilterYUV2RGB || type == kGLFilterYUV2RGBA)
01075 {
01076 glMultiTexCoord2f(GL_TEXTURE1, t_left_uv, t_bottom_uv);
01077 glMultiTexCoord2f(GL_TEXTURE2, t_left_uv, t_bottom_uv);
01078 if (type == kGLFilterYUV2RGBA)
01079 glMultiTexCoord2f(GL_TEXTURE3, t_left_uv, t_bottom);
01080 }
01081 glVertex2f(vleft, vbot);
01082 glEnd();
01083
01084
01085 if (type == kGLFilterResize && filters.count(kGLFilterYUV2RGBA))
01086 glDisable(GL_BLEND);
01087
01088
01089 if (!(type == kGLFilterNone || type == kGLFilterResize))
01090 {
01091 gl_context->BindFragmentProgram(0);
01092 glDisable(GL_FRAGMENT_PROGRAM_ARB);
01093 }
01094
01095
01096 if (filter->outputBuffer != kDefaultBuffer || frameBuffer)
01097 gl_context->BindFramebuffer(0);
01098
01099 inputs = filter->frameBufferTextures;
01100 inputsize = videoSize;
01101 }
01102
01103 currentFrameNum = frame;
01104 inputUpdated = false;
01105 }
01106
01107 void OpenGLVideo::Rotate(vector<GLuint> *target)
01108 {
01109 if (target->size() < 2)
01110 return;
01111
01112 GLuint tmp = (*target)[target->size() - 1];
01113 for (uint i = target->size() - 1; i > 0; i--)
01114 (*target)[i] = (*target)[i - 1];
01115
01116 (*target)[0] = tmp;
01117 }
01118
01119
01120 int OpenGLVideo::SetPictureAttribute(
01121 PictureAttribute attribute, int newValue)
01122 {
01123 if (!useColourControl)
01124 return -1;
01125
01126 int ret = -1;
01127 switch (attribute)
01128 {
01129 case kPictureAttribute_Brightness:
01130 ret = newValue;
01131 pictureAttribs[attribute] = (newValue * 0.02f) - 0.5f;
01132 break;
01133 case kPictureAttribute_Contrast:
01134 case kPictureAttribute_Colour:
01135 ret = newValue;
01136 pictureAttribs[attribute] = (newValue * 0.02f);
01137 break;
01138 case kPictureAttribute_Hue:
01139 break;
01140 default:
01141 break;
01142 }
01143
01144 return ret;
01145 }
01146
01147 PictureAttributeSupported
01148 OpenGLVideo::GetSupportedPictureAttributes(void) const
01149 {
01150 return (!useColourControl) ?
01151 kPictureAttributeSupported_None :
01152 (PictureAttributeSupported)
01153 (kPictureAttributeSupported_Brightness |
01154 kPictureAttributeSupported_Contrast |
01155 kPictureAttributeSupported_Colour);
01156 }
01157
01158
01159 void OpenGLVideo::SetTextureFilters(vector<GLuint> *textures, int filt)
01160 {
01161 if (textures->empty())
01162 return;
01163
01164 for (uint i = 0; i < textures->size(); i++)
01165 gl_context->SetupTextureFilters((*textures)[i], filt);
01166 }
01167
01168
01169 OpenGLFilterType OpenGLVideo::StringToFilter(const QString &filter)
01170 {
01171 OpenGLFilterType ret = kGLFilterNone;
01172
01173 if (filter.contains("master"))
01174 ret = kGLFilterYUV2RGB;
01175 else if (filter.contains("osd"))
01176 ret = kGLFilterYUV2RGBA;
01177 else if (filter.contains("openglkerneldeint"))
01178 ret = kGLFilterKernelDeint;
01179 else if (filter.contains("opengllinearblend"))
01180 ret = kGLFilterLinearBlendDeint;
01181 else if (filter.contains("openglonefield"))
01182 ret = kGLFilterOneFieldDeint;
01183 else if (filter.contains("openglbobdeint"))
01184 ret = kGLFilterBobDeintDFR;
01185 else if (filter.contains("opengldoubleratelinearblend"))
01186 ret = kGLFilterLinearBlendDeintDFR;
01187 else if (filter.contains("opengldoubleratekerneldeint"))
01188 ret = kGLFilterKernelDeintDFR;
01189 else if (filter.contains("opengldoublerateonefield"))
01190 ret = kGLFilterOneFieldDeintDFR;
01191 else if (filter.contains("opengldoubleratefieldorder"))
01192 ret = kGLFilterFieldOrderDFR;
01193 else if (filter.contains("resize"))
01194 ret = kGLFilterResize;
01195
01196 return ret;
01197 }
01198
01199
01200 QString OpenGLVideo::FilterToString(OpenGLFilterType filt)
01201 {
01202 switch (filt)
01203 {
01204 case kGLFilterNone:
01205 break;
01206 case kGLFilterYUV2RGB:
01207 return "master";
01208 case kGLFilterYUV2RGBA:
01209 return "osd";
01210 case kGLFilterKernelDeint:
01211 return "openglkerneldeint";
01212 case kGLFilterLinearBlendDeint:
01213 return "opengllinearblend";
01214 case kGLFilterOneFieldDeint:
01215 return "openglonefield";
01216 case kGLFilterBobDeintDFR:
01217 return "openglbobdeint";
01218 case kGLFilterLinearBlendDeintDFR:
01219 return "opengldoubleratelinearblend";
01220 case kGLFilterKernelDeintDFR:
01221 return "opengldoubleratekerneldeint";
01222 case kGLFilterOneFieldDeintDFR:
01223 return "opengldoublerateonefield";
01224 case kGLFilterFieldOrderDFR:
01225 return "opengldoubleratefieldorder";
01226 case kGLFilterResize:
01227 return "resize";
01228 }
01229
01230 return "";
01231 }
01232
01233 static const QString yuv2rgb1a =
01234 "ATTRIB ytex = fragment.texcoord[0];"
01235 "ATTRIB uvtex = fragment.texcoord[1];"
01236 "TEMP res, tmp;";
01237
01238 static const QString yuv2rgb1b =
01239 "TEMP alpha;"
01240 "TEX alpha, ytex, texture[3], %1;";
01241
01242 static const QString yuv2rgb1c =
01243 "TEX res, ytex, texture[0], %1;"
01244 "TEX tmp.x, uvtex, texture[1], %1;"
01245 "TEX tmp.y, uvtex, texture[2], %1;";
01246
01247 static const QString yuv2rgb2 =
01248 "PARAM adj = program.env[0];"
01249 "SUB res, res, 0.5;"
01250 "MAD res, res, adj.yyyy, adj.xxxx;"
01251 "SUB tmp, tmp, { 0.5, 0.5 };"
01252 "MAD tmp, adj.zzzz, tmp, 0.5;";
01253
01254 static const QString yuv2rgb3 =
01255 "MAD res, res, 1.164, -0.063;"
01256 "SUB tmp, tmp, { 0.5, 0.5 };"
01257 "MAD res, { 0, -.392, 2.017 }, tmp.xxxw, res;";
01258
01259 static const QString yuv2rgb4 =
01260 "MAD result.color, { 1.596, -.813, 0, 0 }, tmp.yyyw, res;";
01261
01262 static const QString yuv2rgb5 =
01263 "MAD result.color, { 0, -.813, 1.596, 0 }, tmp.yyyw, res.bgra;";
01264
01265 static const QString yuv2rgb6 =
01266 "MOV result.color.a, alpha.a;";
01267
01268
01269 QString OpenGLVideo::GetProgramString(OpenGLFilterType name)
01270 {
01271 QString ret =
01272 "!!ARBfp1.0\n"
01273 "OPTION ARB_precision_hint_fastest;";
01274
01275 switch (name)
01276 {
01277 case kGLFilterYUV2RGB:
01278 ret = ret + yuv2rgb1a + yuv2rgb1c;
01279 if (useColourControl)
01280 ret += yuv2rgb2;
01281 ret += yuv2rgb3;
01282 ret += frameBuffer ? yuv2rgb5 : yuv2rgb4;
01283 break;
01284
01285 case kGLFilterYUV2RGBA:
01286 ret = ret + yuv2rgb1a + yuv2rgb1b + yuv2rgb1c;
01287 if (useColourControl)
01288 ret += yuv2rgb2;
01289 ret = ret + yuv2rgb3 + yuv2rgb4 + yuv2rgb6;
01290 break;
01291
01292 case kGLFilterKernelDeint:
01293 ret +=
01294 "ATTRIB tex = fragment.texcoord[0];"
01295 "PARAM off = program.env[0];"
01296 "TEMP sam, pos, cum, cur, field, mov;"
01297 "RCP field, off.x;"
01298 "MUL field, tex.yyyy, field;"
01299 "FRC field, field;"
01300 "SUB field, field, 0.5;"
01301 "TEX sam, tex, texture[1], %1;"
01302 "TEX cur, tex, texture[0], %1;"
01303 "SUB mov, cur, sam;"
01304 "MUL cum, sam, 0.125;"
01305 "MAD cum, cur, 0.125, cum;"
01306 "ABS mov, mov;"
01307 "SUB mov, mov, 0.12;"
01308 "ADD pos, tex, off.wyww;"
01309 "TEX sam, pos, texture[0], %1;"
01310 "MAD cum, sam, 0.5, cum;"
01311 "SUB pos, tex, off.wyww;"
01312 "TEX sam, pos, texture[0], %1;"
01313 "MAD cum, sam, 0.5, cum;"
01314 "MAD pos, off.wyww, 2.0, tex;"
01315 "TEX sam, pos, texture[0], %1;"
01316 "MAD cum, sam, -0.0625, cum;"
01317 "TEX sam, pos, texture[1], %1;"
01318 "MAD cum, sam, -0.0625, cum;"
01319 "MAD pos, off.wyww, -2.0, tex;"
01320 "TEX sam, pos, texture[0], %1;"
01321 "MAD cum, sam, -0.0625, cum;"
01322 "TEX sam, pos, texture[1], %1;"
01323 "MAD cum, sam, -0.0625, cum;"
01324 "CMP cum, mov, cur, cum;"
01325 "CMP result.color, field, cum, cur;";
01326 break;
01327
01328 case kGLFilterLinearBlendDeintDFR:
01329 ret +=
01330 "ATTRIB tex = fragment.texcoord[0];"
01331 "PARAM off = program.env[0];"
01332 "TEMP field, top, bot, current, previous, next, other, mov;"
01333 "TEX next, tex, texture[0], %1;"
01334 "TEX current, tex, texture[1], %1;"
01335 "TEX previous, tex, texture[2], %1;"
01336 "ADD top, tex, off.wyww;"
01337 "TEX other, top, texture[1], %1;"
01338 "SUB top, tex, off.wyww;"
01339 "TEX bot, top, texture[1], %1;"
01340 "LRP other, 0.5, other, bot;"
01341 "RCP field, off.x;"
01342 "MUL field, tex.yyyy, field;"
01343 "FRC field, field;"
01344 "SUB field, field, 0.5;"
01345 "SUB top, current, next;"
01346 "SUB bot, current, previous;"
01347 "CMP mov, field, bot, top;"
01348 "ABS mov, mov;"
01349 "SUB mov, mov, 0.12;"
01350 "CMP other, mov, current, other;"
01351 "CMP top, field, other, current;"
01352 "CMP bot, field, current, other;"
01353 "CMP result.color, off.y, top, bot;";
01354 break;
01355
01356 case kGLFilterOneFieldDeintDFR:
01357 ret +=
01358 "ATTRIB tex = fragment.texcoord[0];"
01359 "PARAM off = program.env[0];"
01360 "TEMP field, top, bot, current, previous, next, other, mov;"
01361 "TEX next, tex, texture[0], %1;"
01362 "TEX current, tex, texture[1], %1;"
01363 "TEX previous, tex, texture[2], %1;"
01364 "ADD top, tex, off.wyww;"
01365 "TEX other, top, texture[1], %1;"
01366 "RCP field, off.x;"
01367 "MUL field, tex.yyyy, field;"
01368 "FRC field, field;"
01369 "SUB field, field, 0.5;"
01370 "SUB top, current, next;"
01371 "SUB bot, current, previous;"
01372 "CMP mov, field, bot, top;"
01373 "ABS mov, mov;"
01374 "SUB mov, mov, 0.12;"
01375 "CMP other, mov, current, other;"
01376 "CMP top, field, other, current;"
01377 "CMP bot, field, current, other;"
01378 "CMP result.color, off.y, top, bot;";
01379 break;
01380
01381 case kGLFilterKernelDeintDFR:
01382 ret +=
01383 "ATTRIB tex = fragment.texcoord[0];"
01384 "PARAM off = program.env[0];"
01385 "TEMP sam, pos, bot, top, cur, pre, nex, field, mov;"
01386 "RCP field, off.x;"
01387 "MUL field, tex.yyyy, field;"
01388 "FRC field, field;"
01389 "SUB field, field, 0.5;"
01390 "TEX pre, tex, texture[2], %1;"
01391 "TEX cur, tex, texture[1], %1;"
01392 "TEX nex, tex, texture[0], %1;"
01393 "SUB top, nex, cur;"
01394 "SUB bot, pre, cur;"
01395 "CMP mov, field, bot, top;"
01396 "ABS mov, mov;"
01397 "SUB mov, mov, 0.12;"
01398 "MUL bot, pre, 0.125;"
01399 "MAD bot, cur, 0.125, bot;"
01400 "MUL top, cur, 0.125;"
01401 "MAD top, nex, 0.125, top;"
01402 "ADD pos, tex, off.wyww;"
01403 "TEX sam, pos, texture[1], %1;"
01404 "MAD bot, sam, 0.5, bot;"
01405 "MAD top, sam, 0.5, top;"
01406 "SUB pos, tex, off.wyww;"
01407 "TEX sam, pos, texture[1], %1;"
01408 "MAD bot, sam, 0.5, bot;"
01409 "MAD top, sam, 0.5, top;"
01410 "MAD pos, off.wyww, 2.0, tex;"
01411 "TEX sam, pos, texture[1], %1;"
01412 "MAD bot, sam, -0.0625, bot;"
01413 "MAD top, sam, -0.0625, top;"
01414 "TEX sam, pos, texture[2], %1;"
01415 "MAD bot, sam, -0.0625, bot;"
01416 "TEX sam, pos, texture[0], %1;"
01417 "MAD top, sam, -0.0625, top;"
01418 "MAD pos, off.wyww, -2.0, tex;"
01419 "TEX sam, pos, texture[1], %1;"
01420 "MAD bot, sam, -0.0625, bot;"
01421 "MAD top, sam, -0.0625, top;"
01422 "TEX sam, pos, texture[2], %1;"
01423 "MAD bot, sam, -0.0625, bot;"
01424 "TEX sam, pos, texture[0], %1;"
01425 "MAD top, sam, -0.0625, top;"
01426 "CMP top, mov, cur, top;"
01427 "CMP bot, mov, cur, bot;"
01428 "CMP top, field, top, cur;"
01429 "CMP bot, field, cur, bot;"
01430 "CMP result.color, off.y, top, bot;";
01431 break;
01432
01433 case kGLFilterBobDeintDFR:
01434 case kGLFilterOneFieldDeint:
01435 ret +=
01436 "ATTRIB tex = fragment.texcoord[0];"
01437 "PARAM off = program.env[0];"
01438 "TEMP field, top, bottom, current, other;"
01439 "TEX current, tex, texture[0], %1;"
01440 "RCP field, off.x;"
01441 "MUL field, tex.yyyy, field;"
01442 "FRC field, field;"
01443 "SUB field, field, 0.5;"
01444 "ADD top, tex, off.wyww;"
01445 "TEX other, top, texture[0], %1;"
01446 "CMP top, field, other, current;"
01447 "CMP bottom, field, current, other;"
01448 "CMP result.color, off.y, top, bottom;";
01449 break;
01450
01451 case kGLFilterLinearBlendDeint:
01452 ret +=
01453 "ATTRIB tex = fragment.texcoord[0];"
01454 "PARAM off = program.env[0];"
01455 "TEMP mov, field, cur, pre, pos;"
01456 "RCP field, off.x;"
01457 "MUL field, tex.yyyy, field;"
01458 "FRC field, field;"
01459 "SUB field, field, 0.5;"
01460 "TEX cur, tex, texture[0], %1;"
01461 "TEX pre, tex, texture[1], %1;"
01462 "SUB mov, cur, pre;"
01463 "ABS mov, mov;"
01464 "SUB mov, mov, 0.12;"
01465 "ADD pos, tex, off.wyww;"
01466 "TEX pre, pos, texture[0], %1;"
01467 "SUB pos, tex, off.wyww;"
01468 "TEX pos, pos, texture[0], %1;"
01469 "LRP pre, 0.5, pos, pre;"
01470 "CMP pre, field, pre, cur;"
01471 "CMP result.color, mov, cur, pre;";
01472 break;
01473
01474 case kGLFilterFieldOrderDFR:
01475 ret +=
01476 "ATTRIB tex = fragment.texcoord[0];"
01477 "PARAM off = program.env[0];"
01478 "TEMP field, cur, pre, bot;"
01479 "TEX cur, tex, texture[0], %1;"
01480 "TEX pre, tex, texture[1], %1;"
01481 "RCP field, off.x;"
01482 "MUL field, tex.yyyy, field;"
01483 "FRC field, field;"
01484 "SUB field, field, 0.5;"
01485 "CMP bot, off.y, pre, cur;"
01486 "CMP result.color, field, bot, cur;";
01487
01488 break;
01489
01490 case kGLFilterNone:
01491 case kGLFilterResize:
01492 break;
01493
01494 default:
01495 VERBOSE(VB_PLAYBACK, LOC_ERR + "Unknown fragment program.");
01496 break;
01497 }
01498
01499 return ret + "END";
01500 }