1 | #include <cmath>
|
---|
2 |
|
---|
3 | using namespace std;
|
---|
4 |
|
---|
5 | // MythTV videout headers
|
---|
6 | #include "videoout_opengl.h"
|
---|
7 | #include "osd.h"
|
---|
8 | #include "osdsurface.h"
|
---|
9 | #include "util-opengl.h"
|
---|
10 | #include "util-x11.h"
|
---|
11 | #include "videodisplayprofile.h"
|
---|
12 |
|
---|
13 | // MythTV General headers
|
---|
14 | #include "../libavcodec/avcodec.h"
|
---|
15 | #include "mythconfig.h"
|
---|
16 | #include "mythcontext.h"
|
---|
17 | #include "filtermanager.h"
|
---|
18 | #include "NuppelVideoPlayer.h"
|
---|
19 | #define IGNORE_TV_PLAY_REC
|
---|
20 | #include "tv.h"
|
---|
21 |
|
---|
22 | extern "C" {
|
---|
23 | #define XMD_H 1
|
---|
24 | #include <X11/extensions/xf86vmode.h>
|
---|
25 | #include <X11/extensions/Xinerama.h>
|
---|
26 | }
|
---|
27 |
|
---|
28 | #define LOC QString("VideoOutputOpengl: ")
|
---|
29 | #define LOC_ERR QString("VideoOutputOpengl Error: ")
|
---|
30 |
|
---|
31 | VideoOutputOpengl::VideoOutputOpengl()
|
---|
32 | : VideoOutput(),
|
---|
33 | display_res(NULL), global_lock(true),
|
---|
34 | gl(new OpenglContext), videochain(NULL), pipchain(NULL), osdchain(NULL),
|
---|
35 | render_onscreen(true),
|
---|
36 | gl_osd(false), actually_draw_pip(false), argb_frame(NULL)
|
---|
37 | {
|
---|
38 | bzero(&av_pause_frame, sizeof(av_pause_frame));
|
---|
39 | use_colourcontrols = gContext->GetNumSetting(
|
---|
40 | "UseOutputPictureControls", 0);
|
---|
41 | allowpreviewepg = false;
|
---|
42 | }
|
---|
43 |
|
---|
44 | VideoOutputOpengl::~VideoOutputOpengl()
|
---|
45 | {
|
---|
46 | X11L;
|
---|
47 | if (videochain)
|
---|
48 | delete videochain;
|
---|
49 | if (pipchain)
|
---|
50 | delete pipchain;
|
---|
51 | if (osdchain)
|
---|
52 | delete osdchain;
|
---|
53 | if (gl)
|
---|
54 | delete gl;
|
---|
55 | X11U;
|
---|
56 | if (argb_frame)
|
---|
57 | delete argb_frame;
|
---|
58 | DeleteBuffers(true);
|
---|
59 | if (display_res)
|
---|
60 | display_res->SwitchToGUI();
|
---|
61 | }
|
---|
62 |
|
---|
63 | bool VideoOutputOpengl::Init(int width, int height, float aspect,
|
---|
64 | WId winid, int winx, int winy, int winw,
|
---|
65 | int winh, WId embedid)
|
---|
66 | {
|
---|
67 | if (piptype > kPIPOn)
|
---|
68 | {
|
---|
69 | VERBOSE(VB_PLAYBACK, LOC + "Use NullVideo for Opengl PiP.");
|
---|
70 | return false;
|
---|
71 | }
|
---|
72 |
|
---|
73 | if (gContext->GetNumSetting("UseVideoModes", 0) &&
|
---|
74 | render_onscreen && !piptype)
|
---|
75 | display_res = DisplayRes::GetDisplayRes();
|
---|
76 |
|
---|
77 | if (winid <= 0)
|
---|
78 | {
|
---|
79 | VERBOSE(VB_PLAYBACK, LOC_ERR + "Invalid Window ID.");
|
---|
80 | return false;
|
---|
81 | }
|
---|
82 | VideoOutput::Init(width, height, aspect,
|
---|
83 | winid, winx, winy, winw, winh,
|
---|
84 | embedid);
|
---|
85 | if (!gl->Create(winid, display_visible_rect.width(),
|
---|
86 | display_visible_rect.height(),
|
---|
87 | render_onscreen))
|
---|
88 | return false;
|
---|
89 | X11S(gl->Init());
|
---|
90 | InitDisplayMeasurements(width, height);
|
---|
91 | MoveResize();
|
---|
92 |
|
---|
93 | X11L;
|
---|
94 | gl->MakeCurrent(true);
|
---|
95 | videochain = new OpenglVideo();
|
---|
96 | bool success = videochain->Init(gl, use_colourcontrols,
|
---|
97 | render_onscreen, video_dim,
|
---|
98 | display_visible_rect,
|
---|
99 | display_video_rect, true);
|
---|
100 | gl->MakeCurrent(false);
|
---|
101 | X11U;
|
---|
102 | if (!success)
|
---|
103 | return false;
|
---|
104 | if (!InitSetupBuffers())
|
---|
105 | return false;
|
---|
106 |
|
---|
107 | db_vdisp_profile->SetVideoRenderer("opengl");
|
---|
108 | if (use_colourcontrols)
|
---|
109 | InitPictureAttributes();
|
---|
110 |
|
---|
111 | if (db_vdisp_profile->GetOSDRenderer() == "opengl")
|
---|
112 | gl_osd = true;
|
---|
113 |
|
---|
114 | if (gl_osd && render_onscreen && !piptype)
|
---|
115 | {
|
---|
116 | X11L;
|
---|
117 | gl->MakeCurrent(true);
|
---|
118 | osdchain = new OpenglVideo();
|
---|
119 | if (!osdchain->Init(gl, use_colourcontrols,
|
---|
120 | render_onscreen, QSize(display_visible_rect.width(),
|
---|
121 | display_visible_rect.height()),
|
---|
122 | display_visible_rect,
|
---|
123 | display_visible_rect, false, true))
|
---|
124 | {
|
---|
125 | delete osdchain;
|
---|
126 | osdchain = NULL;
|
---|
127 | gl_osd = false;
|
---|
128 | }
|
---|
129 | gl->MakeCurrent(false);
|
---|
130 | X11U;
|
---|
131 | }
|
---|
132 | return true;
|
---|
133 | }
|
---|
134 |
|
---|
135 | bool VideoOutputOpengl::SetDeinterlacingEnabled(bool enable)
|
---|
136 | {
|
---|
137 | if (!videochain)
|
---|
138 | return false;
|
---|
139 |
|
---|
140 | if (enable && m_deinterlacing)
|
---|
141 | return m_deinterlacing;
|
---|
142 |
|
---|
143 | if (enable)
|
---|
144 | {
|
---|
145 | if (m_deintfiltername == "")
|
---|
146 | return SetupDeinterlace(enable);
|
---|
147 | if (m_deintfiltername.contains("opengl"))
|
---|
148 | {
|
---|
149 | if (videochain->GetDeinterlacer() == "")
|
---|
150 | return SetupDeinterlace(enable);
|
---|
151 | }
|
---|
152 | else if (!m_deintfiltername.contains("opengl"))
|
---|
153 | {
|
---|
154 | // make sure opengl deinterlacing is disabled
|
---|
155 | X11S(videochain->SetDeinterlacing(false));
|
---|
156 | if (!m_deintFiltMan || !m_deintFilter)
|
---|
157 | return VideoOutput::SetupDeinterlace(enable);
|
---|
158 | }
|
---|
159 | }
|
---|
160 |
|
---|
161 | if (videochain)
|
---|
162 | X11S(videochain->SetDeinterlacing(enable));
|
---|
163 | m_deinterlacing = enable;
|
---|
164 | return m_deinterlacing;
|
---|
165 | }
|
---|
166 |
|
---|
167 | bool VideoOutputOpengl::SetupDeinterlace(bool interlaced,
|
---|
168 | const QString& overridefilter)
|
---|
169 | {
|
---|
170 | m_deintfiltername = db_vdisp_profile->GetFilteredDeint(overridefilter);
|
---|
171 |
|
---|
172 | if (!m_deintfiltername.contains("opengl"))
|
---|
173 | {
|
---|
174 | X11S(videochain->SetDeinterlacing(false));
|
---|
175 | videochain->SetSoftwareDeinterlacer("");
|
---|
176 | VideoOutput::SetupDeinterlace(interlaced, overridefilter);
|
---|
177 | if (m_deinterlacing)
|
---|
178 | videochain->SetSoftwareDeinterlacer(m_deintfiltername);
|
---|
179 | return m_deinterlacing;
|
---|
180 | }
|
---|
181 |
|
---|
182 | // clear any non opengl filters
|
---|
183 | if (m_deintFiltMan)
|
---|
184 | {
|
---|
185 | delete m_deintFiltMan;
|
---|
186 | m_deintFiltMan = NULL;
|
---|
187 | }
|
---|
188 | if (m_deintFilter)
|
---|
189 | {
|
---|
190 | delete m_deintFilter;
|
---|
191 | m_deintFilter = NULL;
|
---|
192 | }
|
---|
193 |
|
---|
194 | if (m_deinterlacing == interlaced)
|
---|
195 | return m_deinterlacing;
|
---|
196 | m_deinterlacing = interlaced;
|
---|
197 |
|
---|
198 | if (!videochain)
|
---|
199 | return false;
|
---|
200 |
|
---|
201 | if (m_deinterlacing && !m_deintfiltername.isEmpty())
|
---|
202 | {
|
---|
203 | if (videochain->GetDeinterlacer() != m_deintfiltername)
|
---|
204 | {
|
---|
205 | X11L;
|
---|
206 | if (!videochain->AddDeinterlacer(m_deintfiltername))
|
---|
207 | {
|
---|
208 | VERBOSE(VB_IMPORTANT, LOC +
|
---|
209 | QString("Couldn't load deinterlace filter %1")
|
---|
210 | .arg(m_deintfiltername));
|
---|
211 | m_deinterlacing = false;
|
---|
212 | m_deintfiltername = "";
|
---|
213 | }
|
---|
214 | else
|
---|
215 | {
|
---|
216 | VERBOSE(VB_PLAYBACK, LOC +
|
---|
217 | QString("Using deinterlace method %1")
|
---|
218 | .arg(m_deintfiltername));
|
---|
219 | }
|
---|
220 | X11U;
|
---|
221 | }
|
---|
222 | }
|
---|
223 | X11S(videochain->SetDeinterlacing(m_deinterlacing));
|
---|
224 | return m_deinterlacing;
|
---|
225 | }
|
---|
226 |
|
---|
227 | void VideoOutputOpengl::GetOSDBounds(QRect &total, QRect &visible,
|
---|
228 | float &visible_aspect,
|
---|
229 | float &font_scaling) const
|
---|
230 | {
|
---|
231 | if (gl_osd)
|
---|
232 | {
|
---|
233 | total = display_visible_rect;
|
---|
234 | visible = display_visible_rect;
|
---|
235 | visible_aspect = (float) display_aspect;
|
---|
236 | font_scaling = 1.0f;
|
---|
237 | return;
|
---|
238 | }
|
---|
239 | VideoOutput::GetOSDBounds(total, visible, visible_aspect, font_scaling);
|
---|
240 | }
|
---|
241 |
|
---|
242 | void VideoOutputOpengl::PrepareFrame(VideoFrame *buffer, FrameScanType t)
|
---|
243 | {
|
---|
244 | if (!buffer)
|
---|
245 | buffer = vbuffers.GetScratchFrame();
|
---|
246 |
|
---|
247 | framesPlayed = buffer->frameNumber + 1;
|
---|
248 |
|
---|
249 | // TODO should cope with YUV422P, rgb24, argb32 etc
|
---|
250 | if (buffer->codec != FMT_YV12)
|
---|
251 | return;
|
---|
252 |
|
---|
253 | X11L;
|
---|
254 | gl->MakeCurrent(true);
|
---|
255 | videochain->Show(t, m_deinterlacing, framesPlayed);
|
---|
256 |
|
---|
257 | if (actually_draw_pip && render_onscreen && pipchain)
|
---|
258 | pipchain->Show(t, m_deinterlacing, framesPlayed);
|
---|
259 |
|
---|
260 | if (osdchain && render_onscreen && actually_draw_osd)
|
---|
261 | osdchain->Show(t, m_deinterlacing, framesPlayed);
|
---|
262 | glFlush();
|
---|
263 | gl->MakeCurrent(false);
|
---|
264 | X11U;
|
---|
265 | }
|
---|
266 |
|
---|
267 | void VideoOutputOpengl::ShowPip(VideoFrame *frame,
|
---|
268 | NuppelVideoPlayer *pipplayer)
|
---|
269 | {
|
---|
270 | (void) frame;
|
---|
271 | actually_draw_pip = false;
|
---|
272 | if (!pipplayer)
|
---|
273 | return;
|
---|
274 |
|
---|
275 | int pipw, piph;
|
---|
276 | VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
|
---|
277 | float pipVideoAspect = pipplayer->GetVideoAspect();
|
---|
278 | uint pipVideoWidth = pipplayer->GetVideoWidth();
|
---|
279 | uint pipVideoHeight = pipplayer->GetVideoHeight();
|
---|
280 |
|
---|
281 | // If PiP is not initialized to values we like, silently ignore the frame.
|
---|
282 | if ((pipVideoAspect <= 0) || !pipimage ||
|
---|
283 | !pipimage->buf || pipimage->codec != FMT_YV12)
|
---|
284 | {
|
---|
285 | pipplayer->ReleaseCurrentFrame(pipimage);
|
---|
286 | return;
|
---|
287 | }
|
---|
288 |
|
---|
289 | QRect position = GetPIPRect(db_pip_location, pipplayer);
|
---|
290 |
|
---|
291 | if (!pipchain)
|
---|
292 | {
|
---|
293 | VERBOSE(VB_PLAYBACK, LOC + "Initialise PiP.");
|
---|
294 | pipchain = new OpenglVideo();
|
---|
295 | bool success = pipchain->Init(gl, use_colourcontrols,
|
---|
296 | true, QSize(pipVideoWidth, pipVideoHeight),
|
---|
297 | position,
|
---|
298 | position, false);
|
---|
299 | success &= pipchain->AddDeinterlacer("openglonefield");
|
---|
300 | pipchain->SetMasterViewport(videochain->GetViewPort());
|
---|
301 | if (!success)
|
---|
302 | {
|
---|
303 | pipplayer->ReleaseCurrentFrame(pipimage);
|
---|
304 | return;
|
---|
305 | }
|
---|
306 | }
|
---|
307 | QSize current = pipchain->GetVideoSize();
|
---|
308 | if ((uint)current.width() != pipVideoWidth ||
|
---|
309 | (uint)current.height() != pipVideoHeight)
|
---|
310 | {
|
---|
311 | VERBOSE(VB_PLAYBACK, LOC + "Re-initialise PiP.");
|
---|
312 | bool success =pipchain->ReInit(gl, use_colourcontrols,
|
---|
313 | true, QSize(pipVideoWidth, pipVideoHeight),
|
---|
314 | position, position, false);
|
---|
315 | pipchain->SetMasterViewport(videochain->GetViewPort());
|
---|
316 | if (!success)
|
---|
317 | {
|
---|
318 | pipplayer->ReleaseCurrentFrame(pipimage);
|
---|
319 | return;
|
---|
320 | }
|
---|
321 |
|
---|
322 | }
|
---|
323 | pipchain->SetVideoRect(position);
|
---|
324 | pipchain->UpdateInputFrame(pipimage);
|
---|
325 | actually_draw_pip = true;
|
---|
326 | pipplayer->ReleaseCurrentFrame(pipimage);
|
---|
327 | }
|
---|
328 |
|
---|
329 | QRect VideoOutputOpengl::GetPIPRect(int location, NuppelVideoPlayer *pipplayer)
|
---|
330 | {
|
---|
331 | if (!pipplayer || pipplayer == NULL)
|
---|
332 | return VideoOutput::GetPIPRect(location, pipplayer);
|
---|
333 |
|
---|
334 | QRect position;
|
---|
335 | float pipVideoAspect = pipplayer ?
|
---|
336 | (float)pipplayer->GetVideoAspect() : display_aspect;
|
---|
337 | int tmph = (display_visible_rect.height() * db_pip_size) / 100;
|
---|
338 | float pixel_adj = ((float)display_visible_rect.width() /
|
---|
339 | (float)display_visible_rect.height()) / display_aspect;
|
---|
340 | position.setHeight(tmph);
|
---|
341 | position.setWidth((int)(tmph * pipVideoAspect * pixel_adj));
|
---|
342 |
|
---|
343 | int xoff = (int)(display_visible_rect.width() * 0.06);
|
---|
344 | int yoff = (int)(display_visible_rect.height() * 0.06);
|
---|
345 | switch (location)
|
---|
346 | {
|
---|
347 | default:
|
---|
348 | case kPIPTopLeft:
|
---|
349 | yoff = display_visible_rect.height()
|
---|
350 | - position.height() - yoff;
|
---|
351 | break;
|
---|
352 | case kPIPBottomLeft:
|
---|
353 | break;
|
---|
354 | case kPIPTopRight:
|
---|
355 | xoff = display_visible_rect.width()
|
---|
356 | - position.width() - xoff;
|
---|
357 | yoff = display_visible_rect.height()
|
---|
358 | - position.height() - yoff;
|
---|
359 | break;
|
---|
360 | case kPIPBottomRight:
|
---|
361 | xoff = display_visible_rect.width()
|
---|
362 | - position.width() - xoff;
|
---|
363 | break;
|
---|
364 | }
|
---|
365 | position.moveBy(xoff, yoff);
|
---|
366 | return position;
|
---|
367 | }
|
---|
368 |
|
---|
369 | void VideoOutputOpengl::Show(FrameScanType )
|
---|
370 | {
|
---|
371 | X11L;
|
---|
372 | gl->SwapBuffers();
|
---|
373 | X11U;
|
---|
374 | }
|
---|
375 |
|
---|
376 | unsigned char* VideoOutputOpengl::GetARGBFrame(QSize &size)
|
---|
377 | {
|
---|
378 | // TODO
|
---|
379 | (void) size;
|
---|
380 | return NULL;
|
---|
381 | }
|
---|
382 |
|
---|
383 | void VideoOutputOpengl::DrawUnusedRects(bool sync)
|
---|
384 | {
|
---|
385 | (void) sync;
|
---|
386 | }
|
---|
387 |
|
---|
388 | void VideoOutputOpengl::Zoom(int direction)
|
---|
389 | {
|
---|
390 | VideoOutput::Zoom(direction);
|
---|
391 | MoveResize();
|
---|
392 | }
|
---|
393 |
|
---|
394 | void VideoOutputOpengl::InputChanged(int width, int height,
|
---|
395 | float aspect, MythCodecID av_codec_id)
|
---|
396 | {
|
---|
397 | VERBOSE(VB_PLAYBACK, LOC + "InputChanged");
|
---|
398 | QRect current_visible = display_visible_rect;
|
---|
399 | VideoOutput::InputChanged(width, height, aspect, av_codec_id);
|
---|
400 | ResizeForVideo((uint) width, (uint) height);
|
---|
401 | MoveResize();
|
---|
402 |
|
---|
403 | if (videochain)
|
---|
404 | {
|
---|
405 | QSize size = videochain->GetVideoSize();
|
---|
406 | if (width != size.width() ||
|
---|
407 | height != size.height())
|
---|
408 | {
|
---|
409 | X11L;
|
---|
410 | videochain->ReInit(gl, use_colourcontrols,
|
---|
411 | render_onscreen, video_dim,
|
---|
412 | display_visible_rect,
|
---|
413 | display_video_rect, true);
|
---|
414 | X11U;
|
---|
415 | if (pipchain && pipchain != NULL)
|
---|
416 | pipchain->SetMasterViewport(videochain->GetViewPort());
|
---|
417 | CreateBuffers();
|
---|
418 | CreatePauseFrame();
|
---|
419 | }
|
---|
420 | }
|
---|
421 | }
|
---|
422 |
|
---|
423 | void VideoOutputOpengl::MoveResize(void)
|
---|
424 | {
|
---|
425 | VideoOutput::MoveResize();
|
---|
426 | if (videochain)
|
---|
427 | videochain->SetVideoRect(display_video_rect);
|
---|
428 | }
|
---|
429 |
|
---|
430 | bool VideoOutputOpengl::InitSetupBuffers(void)
|
---|
431 | {
|
---|
432 | vbuffers.Init(31, true, 1, 12, 4, 2, false);
|
---|
433 | CreateBuffers();
|
---|
434 | CreatePauseFrame();
|
---|
435 | return true;
|
---|
436 | }
|
---|
437 |
|
---|
438 | void VideoOutputOpengl::CreateBuffers(void)
|
---|
439 | {
|
---|
440 | if (videochain)
|
---|
441 | {
|
---|
442 | QSize size = videochain->GetVideoSize();
|
---|
443 | if (vbuffers.CreateBuffers(size.width(), size.height()))
|
---|
444 | return;
|
---|
445 | }
|
---|
446 | VERBOSE(VB_PLAYBACK, LOC_ERR + "Failed to create buffers");
|
---|
447 | }
|
---|
448 |
|
---|
449 | void VideoOutputOpengl::CreatePauseFrame(void)
|
---|
450 | {
|
---|
451 | vbuffers.LockFrame(&av_pause_frame, "CreatePauseFrame");
|
---|
452 | if (av_pause_frame.buf)
|
---|
453 | {
|
---|
454 | delete [] av_pause_frame.buf;
|
---|
455 | av_pause_frame.buf = NULL;
|
---|
456 | }
|
---|
457 | av_pause_frame.height = vbuffers.GetScratchFrame()->height;
|
---|
458 | av_pause_frame.width = vbuffers.GetScratchFrame()->width;
|
---|
459 | av_pause_frame.bpp = vbuffers.GetScratchFrame()->bpp;
|
---|
460 | av_pause_frame.size = vbuffers.GetScratchFrame()->size;
|
---|
461 | av_pause_frame.frameNumber = vbuffers.GetScratchFrame()->frameNumber;
|
---|
462 | av_pause_frame.buf = new unsigned char[av_pause_frame.size];
|
---|
463 | av_pause_frame.qscale_table = NULL;
|
---|
464 | av_pause_frame.qstride = 0;
|
---|
465 |
|
---|
466 | vbuffers.UnlockFrame(&av_pause_frame, "CreatePauseFrame");
|
---|
467 | }
|
---|
468 |
|
---|
469 | void VideoOutputOpengl::DeleteBuffers(bool delete_pause_frame)
|
---|
470 | {
|
---|
471 | DiscardFrames(true);
|
---|
472 | vbuffers.DeleteBuffers();
|
---|
473 | if (delete_pause_frame)
|
---|
474 | {
|
---|
475 | if (av_pause_frame.buf)
|
---|
476 | {
|
---|
477 | delete [] av_pause_frame.buf;
|
---|
478 | av_pause_frame.buf = NULL;
|
---|
479 | }
|
---|
480 | if (av_pause_frame.qscale_table)
|
---|
481 | {
|
---|
482 | delete [] av_pause_frame.qscale_table;
|
---|
483 | av_pause_frame.qscale_table = NULL;
|
---|
484 | }
|
---|
485 | }
|
---|
486 | }
|
---|
487 |
|
---|
488 | void VideoOutputOpengl::EmbedInWidget(WId wid, int x, int y, int w, int h)
|
---|
489 | {
|
---|
490 | (void) wid;
|
---|
491 | (void) x;
|
---|
492 | (void) y;
|
---|
493 | (void) w;
|
---|
494 | (void) h;
|
---|
495 | }
|
---|
496 |
|
---|
497 | void VideoOutputOpengl::StopEmbedding(void)
|
---|
498 | {
|
---|
499 | }
|
---|
500 |
|
---|
501 | float VideoOutputOpengl::GetDisplayAspect(void)
|
---|
502 | {
|
---|
503 | return display_aspect;
|
---|
504 | }
|
---|
505 |
|
---|
506 | void VideoOutputOpengl::UpdatePauseFrame(void)
|
---|
507 | {
|
---|
508 | vbuffers.LockFrame(&av_pause_frame, "UpdatePauseFrame -- pause");
|
---|
509 |
|
---|
510 | vbuffers.begin_lock(kVideoBuffer_used);
|
---|
511 | VideoFrame *used_frame = NULL;
|
---|
512 | if (vbuffers.size(kVideoBuffer_used) > 0)
|
---|
513 | {
|
---|
514 | used_frame = vbuffers.head(kVideoBuffer_used);
|
---|
515 | if (!vbuffers.TryLockFrame(used_frame, "UpdatePauseFrame -- used"))
|
---|
516 | used_frame = NULL;
|
---|
517 | }
|
---|
518 | if (used_frame)
|
---|
519 | {
|
---|
520 | CopyFrame(&av_pause_frame, used_frame);
|
---|
521 | vbuffers.UnlockFrame(used_frame, "UpdatePauseFrame -- used");
|
---|
522 | }
|
---|
523 | vbuffers.end_lock();
|
---|
524 | if (!used_frame &&
|
---|
525 | vbuffers.TryLockFrame(vbuffers.GetScratchFrame(),
|
---|
526 | "UpdatePauseFrame -- scratch"))
|
---|
527 | {
|
---|
528 | vbuffers.GetScratchFrame()->frameNumber = framesPlayed - 1;
|
---|
529 | CopyFrame(&av_pause_frame, vbuffers.GetScratchFrame());
|
---|
530 | vbuffers.UnlockFrame(vbuffers.GetScratchFrame(),
|
---|
531 | "UpdatePauseFrame -- scratch");
|
---|
532 | }
|
---|
533 | vbuffers.UnlockFrame(&av_pause_frame, "UpdatePauseFrame - used");
|
---|
534 | }
|
---|
535 |
|
---|
536 | void VideoOutputOpengl::ProcessFrame(VideoFrame *frame, OSD *osd,
|
---|
537 | FilterChain *filterList,
|
---|
538 | NuppelVideoPlayer *pipPlayer)
|
---|
539 | {
|
---|
540 | bool pauseframe = false;
|
---|
541 | if (!frame)
|
---|
542 | {
|
---|
543 | frame = vbuffers.GetScratchFrame();
|
---|
544 | CopyFrame(vbuffers.GetScratchFrame(), &av_pause_frame);
|
---|
545 | pauseframe = true;
|
---|
546 | }
|
---|
547 |
|
---|
548 | // disable image processing for offscreen rendering
|
---|
549 | X11L;
|
---|
550 | gl->MakeCurrent(true);
|
---|
551 | if (render_onscreen)
|
---|
552 | {
|
---|
553 | if (filterList)
|
---|
554 | filterList->ProcessFrame(frame);
|
---|
555 | if (m_deinterlacing && m_deintFilter != NULL &&
|
---|
556 | m_deinterlaceBeforeOSD &&
|
---|
557 | !pauseframe)
|
---|
558 | {
|
---|
559 | m_deintFilter->ProcessFrame(frame);
|
---|
560 | }
|
---|
561 | ShowPip(frame, pipPlayer);
|
---|
562 | gl_osd ? DisplayOSD(frame, osd) : VideoOutput::DisplayOSD(frame, osd);
|
---|
563 |
|
---|
564 | if (m_deinterlacing && m_deintFilter != NULL &&
|
---|
565 | !m_deinterlaceBeforeOSD &&
|
---|
566 | !pauseframe)
|
---|
567 | {
|
---|
568 | m_deintFilter->ProcessFrame(frame);
|
---|
569 | }
|
---|
570 | }
|
---|
571 | if (videochain)
|
---|
572 | videochain->UpdateInputFrame(frame);
|
---|
573 | gl->MakeCurrent(false);
|
---|
574 | X11U;
|
---|
575 | }
|
---|
576 |
|
---|
577 | int VideoOutputOpengl::DisplayOSD(VideoFrame *frame, OSD *osd,
|
---|
578 | int stride, int revision)
|
---|
579 | {
|
---|
580 | (void) stride;
|
---|
581 | (void) frame;
|
---|
582 | actually_draw_osd = false;
|
---|
583 | if (!osd || !osdchain)
|
---|
584 | return -1;
|
---|
585 |
|
---|
586 | if (vsz_enabled && videochain)
|
---|
587 | videochain->SetVideoResize(&vsz_desired_display_rect);
|
---|
588 |
|
---|
589 | OSDSurface *surface = osd->Display();
|
---|
590 | if (!surface)
|
---|
591 | return -1;
|
---|
592 |
|
---|
593 | actually_draw_osd = true;
|
---|
594 | bool changed = (-1 == revision) ?
|
---|
595 | surface->Changed() : (surface->GetRevision()!=revision);
|
---|
596 |
|
---|
597 | if (changed)
|
---|
598 | {
|
---|
599 | QSize visible(display_visible_rect.width(),
|
---|
600 | display_visible_rect.height());
|
---|
601 | osdchain->UpdateInput(surface->yuvbuffer, 0, FMT_YV12, visible);
|
---|
602 | osdchain->UpdateInput(surface->alpha, 1, FMT_ALPHA, visible);
|
---|
603 | }
|
---|
604 | return changed;
|
---|
605 | }
|
---|
606 |
|
---|
607 | void VideoOutputOpengl::ShutdownVideoResize(void)
|
---|
608 | {
|
---|
609 | if (!osdchain)
|
---|
610 | {
|
---|
611 | VideoOutput::ShutdownVideoResize();
|
---|
612 | return;
|
---|
613 | }
|
---|
614 | if (videochain)
|
---|
615 | videochain->SetVideoResize(NULL);
|
---|
616 | vsz_enabled = false;
|
---|
617 | }
|
---|
618 |
|
---|
619 | int VideoOutputOpengl::SetPictureAttribute(int attributeType, int newValue)
|
---|
620 | {
|
---|
621 | if (kPictureAttribute_Hue == attributeType)
|
---|
622 | return -1;
|
---|
623 | SetPictureAttributeDBValue(attributeType, newValue);
|
---|
624 | if (videochain && use_colourcontrols)
|
---|
625 | videochain->SetPictureAttribute(attributeType, newValue);
|
---|
626 | return newValue;
|
---|
627 | }
|
---|
628 |
|
---|
629 | int VideoOutputOpengl::GetRefreshRate(void)
|
---|
630 | {
|
---|
631 | XF86VidModeModeLine mode_line;
|
---|
632 | int dot_clock;
|
---|
633 |
|
---|
634 | int ret = False;
|
---|
635 | X11S(ret = XF86VidModeGetModeLine(gl->GetDisplay(), gl->GetScreenNum(),
|
---|
636 | &dot_clock, &mode_line));
|
---|
637 | if (!ret)
|
---|
638 | {
|
---|
639 | VERBOSE(VB_IMPORTANT, LOC_ERR + "GetRefreshRate(): "
|
---|
640 | "X11 ModeLine query failed");
|
---|
641 | return -1;
|
---|
642 | }
|
---|
643 |
|
---|
644 | double rate = (double)((double)(dot_clock * 1000.0) /
|
---|
645 | (double)(mode_line.htotal * mode_line.vtotal));
|
---|
646 |
|
---|
647 | // Assume 60Hz if we can't otherwise determine it.
|
---|
648 | if (rate == 0)
|
---|
649 | rate = 60;
|
---|
650 |
|
---|
651 | if (rate < 20 || rate > 200)
|
---|
652 | {
|
---|
653 | VERBOSE(VB_PLAYBACK, LOC + QString("Unreasonable refresh rate %1Hz "
|
---|
654 | "reported by X").arg(rate));
|
---|
655 | rate = 60;
|
---|
656 | }
|
---|
657 |
|
---|
658 | rate = 1000000.0 / rate;
|
---|
659 |
|
---|
660 | return (int)rate;
|
---|
661 | }
|
---|
662 | void VideoOutputOpengl::ResizeForGui(void)
|
---|
663 | {
|
---|
664 | if (display_res)
|
---|
665 | display_res->SwitchToGUI();
|
---|
666 | }
|
---|
667 |
|
---|
668 | void VideoOutputOpengl::ResizeForVideo(uint width, uint height)
|
---|
669 | {
|
---|
670 | if ((width == 1920 || width == 1440) && height == 1088)
|
---|
671 | height = 1080; // ATSC 1920x1080
|
---|
672 |
|
---|
673 | if (display_res && display_res->SwitchToVideo(width, height))
|
---|
674 | {
|
---|
675 | // Switching to custom display resolution succeeded
|
---|
676 | // Make a note of the new size
|
---|
677 | display_dim = QSize(display_res->GetPhysicalWidth(),
|
---|
678 | display_res->GetPhysicalHeight());
|
---|
679 | display_aspect = display_res->GetAspectRatio();
|
---|
680 |
|
---|
681 | bool fullscreen = !gContext->GetNumSetting("GuiSizeForTV", 0);
|
---|
682 |
|
---|
683 | // if width && height are zero users expect fullscreen playback
|
---|
684 | if (!fullscreen)
|
---|
685 | {
|
---|
686 | int gui_width = 0, gui_height = 0;
|
---|
687 | gContext->GetResolutionSetting("Gui", gui_width, gui_height);
|
---|
688 | fullscreen |= (0 == gui_width && 0 == gui_height);
|
---|
689 | }
|
---|
690 |
|
---|
691 | if (fullscreen)
|
---|
692 | {
|
---|
693 | QSize sz(display_res->GetWidth(), display_res->GetHeight());
|
---|
694 | display_visible_rect = QRect(QPoint(0,0), sz);
|
---|
695 | // Resize X window to fill new resolution
|
---|
696 | X11S(XMoveResizeWindow(gl->GetDisplay(), gl->GetWindow(),
|
---|
697 | display_visible_rect.left(),
|
---|
698 | display_visible_rect.top(),
|
---|
699 | display_visible_rect.width(),
|
---|
700 | display_visible_rect.height()));
|
---|
701 | }
|
---|
702 | }
|
---|
703 | }
|
---|
704 |
|
---|
705 | void VideoOutputOpengl::ResizeForVideo(void)
|
---|
706 | {
|
---|
707 | if (videochain)
|
---|
708 | {
|
---|
709 | QSize size = videochain->GetVideoSize();
|
---|
710 | ResizeForVideo(size.width(), size.height());
|
---|
711 | }
|
---|
712 | }
|
---|
713 |
|
---|
714 | void VideoOutputOpengl::InitDisplayMeasurements(uint width, uint height)
|
---|
715 | {
|
---|
716 | if (display_res)
|
---|
717 | {
|
---|
718 | // The very first Resize needs to be the maximum possible
|
---|
719 | // desired res, because X will mask off anything outside
|
---|
720 | // the initial dimensions
|
---|
721 | X11S(XMoveResizeWindow(gl->GetDisplay(), gl->GetWindow(), 0, 0,
|
---|
722 | display_res->GetMaxWidth(),
|
---|
723 | display_res->GetMaxHeight()));
|
---|
724 | ResizeForVideo(width, height);
|
---|
725 | }
|
---|
726 | else
|
---|
727 | {
|
---|
728 | display_dim = QSize(DisplayWidthMM(gl->GetDisplay(),
|
---|
729 | gl->GetScreenNum()),
|
---|
730 | DisplayHeightMM(gl->GetDisplay(),
|
---|
731 | gl->GetScreenNum()));
|
---|
732 |
|
---|
733 | if (db_display_dim.width() > 0 && db_display_dim.height() > 0)
|
---|
734 | display_dim = db_display_dim;
|
---|
735 | }
|
---|
736 |
|
---|
737 | // Fetch pixel width and height of the display
|
---|
738 | int xbase, ybase, w, h;
|
---|
739 | gContext->GetScreenBounds(xbase, ybase, w, h);
|
---|
740 | // Determine window dimensions in pixels
|
---|
741 | int window_w = w, window_h = h;
|
---|
742 | if (gContext->GetNumSetting("GuiSizeForTV", 0))
|
---|
743 | gContext->GetResolutionSetting("Gui", window_w, window_h);
|
---|
744 | else
|
---|
745 | gContext->GetScreenBounds(xbase, ybase, window_w, window_h);
|
---|
746 | window_w = (window_w) ? window_w : w;
|
---|
747 | window_h = (window_h) ? window_h : h;
|
---|
748 | float pixel_aspect = ((float)w) / ((float)h);
|
---|
749 |
|
---|
750 | VERBOSE(VB_PLAYBACK, LOC + QString(
|
---|
751 | "Pixel dimensions: Screen %1x%2, window %3x%4")
|
---|
752 | .arg(w).arg(h).arg(window_w).arg(window_h));
|
---|
753 |
|
---|
754 | // Determine if we are using Xinerama
|
---|
755 | int event_base, error_base;
|
---|
756 | bool usingXinerama = false;
|
---|
757 | X11S(usingXinerama =
|
---|
758 | (XineramaQueryExtension(gl->GetDisplay(), &event_base, &error_base) &&
|
---|
759 | XineramaIsActive(gl->GetDisplay())));
|
---|
760 |
|
---|
761 | // If the dimensions are invalid, assume square pixels and 17" screen.
|
---|
762 | // Only print warning if this isn't Xinerama, we will fix Xinerama later.
|
---|
763 | if (((display_dim.width() <= 0) || (display_dim.height() <= 0)) &&
|
---|
764 | !usingXinerama)
|
---|
765 | {
|
---|
766 | VERBOSE(VB_GENERAL, LOC + "Physical size of display unknown."
|
---|
767 | "\n\t\t\tAssuming 17\" monitor with square pixels.");
|
---|
768 | display_dim.setHeight(300);
|
---|
769 | display_dim.setWidth((int) round(300 * pixel_aspect));
|
---|
770 | }
|
---|
771 |
|
---|
772 | // If we are using Xinerama the display dimensions can not be trusted.
|
---|
773 | // We need to use the Xinerama monitor aspect ratio from the DB to set
|
---|
774 | // the physical screen width. This assumes the height is correct, which
|
---|
775 | // is more or less true in the typical side-by-side monitor setup.
|
---|
776 | if (usingXinerama)
|
---|
777 | {
|
---|
778 | float displayAspect = gContext->GetFloatSettingOnHost(
|
---|
779 | "XineramaMonitorAspectRatio",
|
---|
780 | gContext->GetHostName(), pixel_aspect);
|
---|
781 | int height = display_dim.height();
|
---|
782 | if (height <= 0)
|
---|
783 | display_dim.setHeight(height = 300);
|
---|
784 | display_dim.setWidth((int) round(height * displayAspect));
|
---|
785 | }
|
---|
786 |
|
---|
787 | VERBOSE(VB_PLAYBACK, LOC +
|
---|
788 | QString("Estimated display dimensions: %1x%2 mm Aspect: %3")
|
---|
789 | .arg(display_dim.width()).arg(display_dim.height())
|
---|
790 | .arg(((float) display_dim.width()) / display_dim.height()));
|
---|
791 |
|
---|
792 | // We must now scale the display measurements to our window size.
|
---|
793 | // If we are running fullscreen this is a no-op.
|
---|
794 | display_dim = QSize((display_dim.width() * window_w) / w,
|
---|
795 | (display_dim.height() * window_h) / h);
|
---|
796 |
|
---|
797 | // Now that we know the physical monitor size, we can
|
---|
798 | // calculate the display aspect ratio pretty simply...
|
---|
799 | display_aspect = ((float)display_dim.width()) / display_dim.height();
|
---|
800 |
|
---|
801 | // If we are using XRandR, use the aspect ratio from it instead...
|
---|
802 | if (display_res)
|
---|
803 | display_aspect = display_res->GetAspectRatio();
|
---|
804 |
|
---|
805 | VERBOSE(VB_PLAYBACK, LOC +
|
---|
806 | QString("Estimated window dimensions: %1x%2 mm Aspect: %3")
|
---|
807 | .arg(display_dim.width()).arg(display_dim.height())
|
---|
808 | .arg(display_aspect));
|
---|
809 | }
|
---|
810 |
|
---|
811 | #undef LOC
|
---|
812 | #undef LOC_ERR
|
---|
813 |
|
---|
814 | #define LOC QString("OpenglVid: ")
|
---|
815 | #define LOC_ERR QString("OpenglVid Error: ")
|
---|
816 |
|
---|
817 | QMap<int,float> OpenglVideo::pictureAttribs;
|
---|
818 |
|
---|
819 | OpenglVideo::OpenglVideo() :
|
---|
820 | convertBuf(NULL)
|
---|
821 | {
|
---|
822 | }
|
---|
823 |
|
---|
824 | OpenglVideo::~OpenglVideo()
|
---|
825 | {
|
---|
826 | Cleanup();
|
---|
827 | }
|
---|
828 |
|
---|
829 | void OpenglVideo::Cleanup()
|
---|
830 | {
|
---|
831 | ShutDownYUV2RGB();
|
---|
832 | gl->MakeCurrent(true);
|
---|
833 | if (frameBuffer)
|
---|
834 | gl->DeleteFrameBuffer(&frameBuffer);
|
---|
835 | if (frameBufferTexture)
|
---|
836 | gl->DeleteTexture(&frameBufferTexture);
|
---|
837 |
|
---|
838 | for (uint i = 0; i < inputTextures.size(); i++)
|
---|
839 | gl->DeleteTexture(&inputTextures[i]);
|
---|
840 | inputTextures.clear();
|
---|
841 |
|
---|
842 | if (!filters.empty())
|
---|
843 | {
|
---|
844 | map<OpenglFilter,Filter>::iterator it;
|
---|
845 | for (it = filters.begin(); it != filters.end(); it++)
|
---|
846 | {
|
---|
847 | if (it->second.fragmentProgram)
|
---|
848 | gl->DeleteProgram(&(it->second.fragmentProgram));
|
---|
849 | vector<GLuint> temp = it->second.frameBuffers;
|
---|
850 | for (uint i = 0; i < temp.size(); i++)
|
---|
851 | gl->DeleteFrameBuffer(&(temp[i]));
|
---|
852 | temp = it->second.frameBufferTextures;
|
---|
853 | for (uint i = 0; i < temp.size(); i++)
|
---|
854 | gl->DeleteTexture(&(temp[i]));
|
---|
855 | }
|
---|
856 | }
|
---|
857 | filters.clear();
|
---|
858 | }
|
---|
859 |
|
---|
860 | bool OpenglVideo::Init(OpenglContext *glcontext, bool colour_control,
|
---|
861 | bool onscreen, QSize video_size, QRect visible_rect,
|
---|
862 | QRect video_rect, bool viewport_control, bool osd)
|
---|
863 | {
|
---|
864 | gl = glcontext;
|
---|
865 | videoSize = video_size;
|
---|
866 | visibleRect = visible_rect;
|
---|
867 | videoRect = video_rect;
|
---|
868 | masterViewportSize = QSize(1920, 1080);
|
---|
869 | QSize rect = videoSize;
|
---|
870 | GetTextureSize(&rect, videoSize);
|
---|
871 | frameBufferRect = QRect(QPoint(0,0), rect);
|
---|
872 | invertVideo = true;
|
---|
873 | softwareDeinterlacer = "";
|
---|
874 | hardwareDeinterlacing = false;
|
---|
875 | useColourControl = colour_control;
|
---|
876 | viewportControl = viewport_control;
|
---|
877 | inputTextureSize = QSize(0,0);
|
---|
878 | convertSize = QSize(0,0);
|
---|
879 | videoResize = false;
|
---|
880 | videoResizeRect = QRect(0,0,0,0);
|
---|
881 | frameBuffer = 0;
|
---|
882 | currentFrameNum = -1;
|
---|
883 | inputUpdated = false;
|
---|
884 |
|
---|
885 | if (!onscreen)
|
---|
886 | {
|
---|
887 | QSize fb_size(visibleRect.width(), visibleRect.height());
|
---|
888 | GetTextureSize(&fb_size, fb_size);
|
---|
889 | if (!AddFrameBuffer(&frameBuffer, &frameBufferTexture, fb_size))
|
---|
890 | return false;
|
---|
891 | }
|
---|
892 |
|
---|
893 | SetViewPort(visibleRect.width(), visibleRect.height());
|
---|
894 | InitOpengl();
|
---|
895 |
|
---|
896 | if (osd)
|
---|
897 | {
|
---|
898 | QSize osdsize(visibleRect.width(),
|
---|
899 | visibleRect.height());
|
---|
900 | GLuint alphatex = CreateVideoTexture(osdsize, &inputTextureSize,
|
---|
901 | gl->TextureSupport() ? false : true);
|
---|
902 | GLuint yuv12tex = CreateVideoTexture(osdsize, &inputTextureSize, true);
|
---|
903 | if ((alphatex && yuv12tex) && AddFilter(kYUV2RGBA))
|
---|
904 | {
|
---|
905 | inputTextures.push_back(yuv12tex);
|
---|
906 | inputTextures.push_back(alphatex);
|
---|
907 | }
|
---|
908 | }
|
---|
909 | else
|
---|
910 | {
|
---|
911 | GLuint yuv12tex = CreateVideoTexture(videoSize,
|
---|
912 | &inputTextureSize, true);
|
---|
913 | if (yuv12tex && AddFilter(kYUV2RGB))
|
---|
914 | inputTextures.push_back(yuv12tex);
|
---|
915 | }
|
---|
916 |
|
---|
917 | if (filters.empty())
|
---|
918 | {
|
---|
919 | if (osd)
|
---|
920 | {
|
---|
921 | Cleanup();
|
---|
922 | return false;
|
---|
923 | }
|
---|
924 | VERBOSE(VB_PLAYBACK, LOC + "Opengl colour conversion failed.");
|
---|
925 | VERBOSE(VB_PLAYBACK, LOC + "Falling back to software conversion.");
|
---|
926 | VERBOSE(VB_PLAYBACK, LOC + "Any opengl filters will also be disabled.");
|
---|
927 | GLuint yuv12tex = CreateVideoTexture(videoSize,
|
---|
928 | &inputTextureSize, false);
|
---|
929 | if (yuv12tex && AddFilter(kRESIZE))
|
---|
930 | inputTextures.push_back(yuv12tex);
|
---|
931 | else
|
---|
932 | {
|
---|
933 | VERBOSE(VB_PLAYBACK, LOC_ERR + "Fatal error.");
|
---|
934 | Cleanup();
|
---|
935 | return false;
|
---|
936 | }
|
---|
937 | }
|
---|
938 | return true;
|
---|
939 | }
|
---|
940 |
|
---|
941 | OpenglFilter OpenglVideo::GetDeintFilter(void)
|
---|
942 | {
|
---|
943 | if (filters.count(kKDEINT))
|
---|
944 | return kKDEINT;
|
---|
945 | if (filters.count(kLINBLEND))
|
---|
946 | return kLINBLEND;
|
---|
947 | if (filters.count(kONEFIELD))
|
---|
948 | return kONEFIELD;
|
---|
949 | if (filters.count(kBOBDEINT))
|
---|
950 | return kBOBDEINT;
|
---|
951 | if (filters.count(kPROGONEFIELD))
|
---|
952 | return kPROGONEFIELD;
|
---|
953 | if (filters.count(kPROGLINBLEND))
|
---|
954 | return kPROGLINBLEND;
|
---|
955 | if (filters.count(kPROGKDEINT))
|
---|
956 | return kPROGKDEINT;
|
---|
957 | return kNOFILT;
|
---|
958 | }
|
---|
959 |
|
---|
960 | bool OpenglVideo::OptimiseFilters(void)
|
---|
961 | {
|
---|
962 | // if video height does not match display rect height, add resize stage
|
---|
963 | // to preserve field information N.B. assumes interlaced
|
---|
964 | // if video rectangle is smaller than display rectangle, add resize stage
|
---|
965 | // to improve performance
|
---|
966 |
|
---|
967 | bool needResize = ((videoSize.height() != videoRect.height()) ||
|
---|
968 | (videoSize.width() < videoRect.width()));
|
---|
969 | if (needResize && !filters.count(kRESIZE))
|
---|
970 | AddFilter(kRESIZE);
|
---|
971 |
|
---|
972 | map<OpenglFilter, Filter>::reverse_iterator it;
|
---|
973 |
|
---|
974 | // add/remove required frame buffer objects
|
---|
975 | // and link filters
|
---|
976 | uint buffers_needed = 1;
|
---|
977 | bool last_filter = true;
|
---|
978 | bool needtorotate = false;
|
---|
979 | int i = filters.size();
|
---|
980 | for (it = filters.rbegin(); it != filters.rend(); it++, i--)
|
---|
981 | {
|
---|
982 | it->second.outputBuffer = kFrameBufferObject;
|
---|
983 | it->second.rotateFrameBuffers = needtorotate;
|
---|
984 | if (!last_filter)
|
---|
985 | {
|
---|
986 | uint buffers_have = it->second.frameBuffers.size();
|
---|
987 | int buffers_diff = buffers_needed - buffers_have;
|
---|
988 | if (buffers_diff > 0)
|
---|
989 | {
|
---|
990 | GLuint tmp_buf, tmp_tex;
|
---|
991 | QSize fb_size(videoSize.width(), videoSize.height());
|
---|
992 | GetTextureSize(&fb_size, fb_size);
|
---|
993 | for (int i = 0; i < buffers_diff; i++)
|
---|
994 | {
|
---|
995 | if (!AddFrameBuffer(&tmp_buf, &tmp_tex, fb_size))
|
---|
996 | return false;
|
---|
997 | else
|
---|
998 | {
|
---|
999 | it->second.frameBuffers.push_back(tmp_buf);
|
---|
1000 | it->second.frameBufferTextures.push_back(tmp_tex);
|
---|
1001 | }
|
---|
1002 | }
|
---|
1003 | }
|
---|
1004 | else if (buffers_diff < 0)
|
---|
1005 | {
|
---|
1006 | for (int i = 0; i > buffers_diff; i--)
|
---|
1007 | {
|
---|
1008 | gl->DeleteFrameBuffer(&(it->second.frameBuffers.back()));
|
---|
1009 | gl->DeleteTexture(&(it->second.frameBufferTextures.back()));
|
---|
1010 | it->second.frameBuffers.pop_back();
|
---|
1011 | it->second.frameBufferTextures.pop_back();
|
---|
1012 | }
|
---|
1013 | }
|
---|
1014 | }
|
---|
1015 | else
|
---|
1016 | {
|
---|
1017 | last_filter = false;
|
---|
1018 | }
|
---|
1019 | buffers_needed = it->second.numInputs;
|
---|
1020 | needtorotate = (it->first == kKDEINT ||
|
---|
1021 | it->first == kLINBLEND ||
|
---|
1022 | it->first == kPROGONEFIELD ||
|
---|
1023 | it->first == kPROGLINBLEND ||
|
---|
1024 | it->first == kPROGKDEINT);
|
---|
1025 | }
|
---|
1026 |
|
---|
1027 | bool deinterlacing = hardwareDeinterlacing;
|
---|
1028 | hardwareDeinterlacing = true;
|
---|
1029 | SetDeinterlacing(false);
|
---|
1030 | if (deinterlacing)
|
---|
1031 | SetDeinterlacing(deinterlacing);
|
---|
1032 | return true;
|
---|
1033 | }
|
---|
1034 |
|
---|
1035 | void OpenglVideo::SetFiltering(void)
|
---|
1036 | {
|
---|
1037 | // filter settings included for performance only
|
---|
1038 | // no (obvious) quality improvement over GL_LINEAR throughout
|
---|
1039 | if (filters.empty())
|
---|
1040 | return;
|
---|
1041 |
|
---|
1042 | if (filters.size() == 1)
|
---|
1043 | {
|
---|
1044 | SetTextureFilters(&inputTextures, GL_LINEAR);
|
---|
1045 | return;
|
---|
1046 | }
|
---|
1047 |
|
---|
1048 | SetTextureFilters(&inputTextures, GL_NEAREST);
|
---|
1049 | vector<GLuint> textures;
|
---|
1050 | map<OpenglFilter,Filter>::iterator it;
|
---|
1051 | for (it = filters.begin(); it != filters.end(); it++)
|
---|
1052 | SetTextureFilters(&(it->second.frameBufferTextures), GL_NEAREST);
|
---|
1053 |
|
---|
1054 | // resize or last active (ie don't need resize) need GL_LINEAR
|
---|
1055 | map<OpenglFilter, Filter>::reverse_iterator rit;
|
---|
1056 | bool next = false;
|
---|
1057 | bool resize = filters.count(kRESIZE);
|
---|
1058 | for (rit = filters.rbegin(); rit != filters.rend(); rit++)
|
---|
1059 | {
|
---|
1060 | if (next && (rit->second.outputBuffer != kNoBuffer))
|
---|
1061 | {
|
---|
1062 | SetTextureFilters(&(rit->second.frameBufferTextures), GL_LINEAR);
|
---|
1063 | return;
|
---|
1064 | break;
|
---|
1065 | }
|
---|
1066 | if (resize)
|
---|
1067 | if (rit->first == kRESIZE)
|
---|
1068 | next = true;
|
---|
1069 | else
|
---|
1070 | if (rit->second.outputBuffer == kDefaultBuffer)
|
---|
1071 | next = true;
|
---|
1072 | }
|
---|
1073 | SetTextureFilters(&inputTextures, GL_LINEAR);
|
---|
1074 | }
|
---|
1075 |
|
---|
1076 | bool OpenglVideo::ReInit(OpenglContext *glcontext, bool colour_control,
|
---|
1077 | bool onscreen, QSize video_size, QRect visible_rect,
|
---|
1078 | QRect video_rect, bool viewport_control, bool osd)
|
---|
1079 | {
|
---|
1080 | VERBOSE(VB_PLAYBACK, LOC + "Reinit");
|
---|
1081 | gl->MakeCurrent(true);
|
---|
1082 | QString harddeint = GetDeinterlacer(); // N.B. only adds back deinterlacer
|
---|
1083 | QString softdeint = softwareDeinterlacer;
|
---|
1084 | bool interlacing = hardwareDeinterlacing;
|
---|
1085 | bool resize = videoResize;
|
---|
1086 | QRect resize_rect = videoResizeRect;
|
---|
1087 |
|
---|
1088 | Cleanup();
|
---|
1089 | bool success = Init(glcontext, colour_control, onscreen, video_size,
|
---|
1090 | visible_rect, video_rect, viewport_control, osd);
|
---|
1091 | if (harddeint != "")
|
---|
1092 | success &= AddDeinterlacer(harddeint);
|
---|
1093 | softwareDeinterlacer = softdeint;
|
---|
1094 | SetDeinterlacing(interlacing);
|
---|
1095 | if (resize)
|
---|
1096 | SetVideoResize(&resize_rect);
|
---|
1097 |
|
---|
1098 | return success;
|
---|
1099 | }
|
---|
1100 |
|
---|
1101 | bool OpenglVideo::AddFilter(OpenglFilter filter)
|
---|
1102 | {
|
---|
1103 | if (filters.count(filter))
|
---|
1104 | return true;
|
---|
1105 |
|
---|
1106 | VERBOSE(VB_PLAYBACK, LOC + QString("Creating %1 filter.")
|
---|
1107 | .arg(FilterToString(filter)));
|
---|
1108 | gl->MakeCurrent(true);
|
---|
1109 | Filter temp;
|
---|
1110 | if (filter == kYUV2RGBA || filter == kLINBLEND || filter == kKDEINT)
|
---|
1111 | temp.numInputs = 2;
|
---|
1112 | else if (filter == kPROGONEFIELD || filter == kPROGKDEINT ||
|
---|
1113 | filter == kPROGLINBLEND)
|
---|
1114 | temp.numInputs = 3;
|
---|
1115 | else
|
---|
1116 | temp.numInputs = 1;
|
---|
1117 |
|
---|
1118 | GLuint program = 0;
|
---|
1119 | if (filter != kNOFILT && filter != kRESIZE)
|
---|
1120 | {
|
---|
1121 | program = AddFragmentProgram(filter);
|
---|
1122 | if (!program)
|
---|
1123 | return false;
|
---|
1124 | }
|
---|
1125 | temp.fragmentProgram = program;
|
---|
1126 | temp.outputBuffer = kDefaultBuffer;
|
---|
1127 | temp.rotateFrameBuffers = false;
|
---|
1128 | temp.frameBuffers.clear();
|
---|
1129 | temp.frameBufferTextures.clear();
|
---|
1130 | filters[filter] = temp;
|
---|
1131 | if (OptimiseFilters())
|
---|
1132 | return true;
|
---|
1133 |
|
---|
1134 | RemoveFilter(filter);
|
---|
1135 | return false;
|
---|
1136 | }
|
---|
1137 |
|
---|
1138 | bool OpenglVideo::RemoveFilter(OpenglFilter filter)
|
---|
1139 | {
|
---|
1140 | if (!filters.count(filter))
|
---|
1141 | return true;
|
---|
1142 |
|
---|
1143 | gl->MakeCurrent(true);
|
---|
1144 | gl->DeleteProgram(&(filters[filter].fragmentProgram));
|
---|
1145 | vector<GLuint> temp;
|
---|
1146 | vector<GLuint>::iterator it;
|
---|
1147 | temp = filters[filter].frameBuffers;
|
---|
1148 | for (it = temp.begin(); it != temp.end(); it++)
|
---|
1149 | gl->DeleteFrameBuffer(&(*(it)));
|
---|
1150 | temp = filters[filter].frameBufferTextures;
|
---|
1151 | for (it = temp.begin(); it != temp.end(); it++)
|
---|
1152 | gl->DeleteTexture(&(*(it)));
|
---|
1153 | filters.erase(filter);
|
---|
1154 | gl->MakeCurrent(false);
|
---|
1155 |
|
---|
1156 | return true;
|
---|
1157 | }
|
---|
1158 |
|
---|
1159 | bool OpenglVideo::AddDeinterlacer(QString filter)
|
---|
1160 | {
|
---|
1161 | QString current_deinterlacer = GetDeinterlacer();
|
---|
1162 | if (current_deinterlacer != "")
|
---|
1163 | {
|
---|
1164 | if (current_deinterlacer == filter)
|
---|
1165 | return true;
|
---|
1166 | else
|
---|
1167 | RemoveFilter(current_deinterlacer);
|
---|
1168 | }
|
---|
1169 | return AddFilter(filter);
|
---|
1170 | }
|
---|
1171 |
|
---|
1172 | GLuint OpenglVideo::AddFragmentProgram(OpenglFilter name)
|
---|
1173 | {
|
---|
1174 | if (!gl->FragProgSupport())
|
---|
1175 | {
|
---|
1176 | VERBOSE(VB_PLAYBACK, LOC_ERR + "Fragment programs not supported");
|
---|
1177 | return false;
|
---|
1178 | }
|
---|
1179 | GLuint ret;
|
---|
1180 | QString program = GetProgramString(name);
|
---|
1181 | program.replace("%1", gl->TextureSupport() ? "RECT" : "2D");
|
---|
1182 | if (gl->CreateProgram(&program, &ret))
|
---|
1183 | {
|
---|
1184 | VERBOSE(VB_PLAYBACK, LOC + QString("Created fragment program %1.")
|
---|
1185 | .arg(FilterToString(name)));
|
---|
1186 | return ret;
|
---|
1187 | }
|
---|
1188 | return 0;
|
---|
1189 | }
|
---|
1190 |
|
---|
1191 | bool OpenglVideo::AddFrameBuffer(GLuint *framebuffer,
|
---|
1192 | GLuint *texture, QSize size)
|
---|
1193 | {
|
---|
1194 | if (!gl->FrameBufSupport())
|
---|
1195 | {
|
---|
1196 | VERBOSE(VB_PLAYBACK, LOC_ERR + "Offscreen rendering not supported.");
|
---|
1197 | return false;
|
---|
1198 | }
|
---|
1199 | GLuint tmp_buf, tmp_tex;
|
---|
1200 | gl->CreateTexture(&tmp_tex);
|
---|
1201 | if(gl->CreateFrameBuffer( &tmp_buf, &tmp_tex, size.width(), size.height()))
|
---|
1202 | {
|
---|
1203 | *framebuffer = tmp_buf;
|
---|
1204 | *texture = tmp_tex;
|
---|
1205 | return true;
|
---|
1206 | }
|
---|
1207 | gl->DeleteTexture(&tmp_tex);
|
---|
1208 | return false;
|
---|
1209 | }
|
---|
1210 |
|
---|
1211 | void OpenglVideo::SetViewPort(uint width, uint height)
|
---|
1212 | {
|
---|
1213 | uint w = max((int)width, videoSize.width());
|
---|
1214 | uint h = max((int)height, videoSize.height());
|
---|
1215 | viewportSize = QSize(w, h);
|
---|
1216 | if (!viewportControl)
|
---|
1217 | return;
|
---|
1218 | VERBOSE(VB_PLAYBACK, LOC +
|
---|
1219 | QString("Viewport: %1x%2").arg(w).arg(h));
|
---|
1220 | ViewPort(w, h);
|
---|
1221 | }
|
---|
1222 |
|
---|
1223 | void OpenglVideo::ViewPort(uint width, uint height)
|
---|
1224 | {
|
---|
1225 | glViewport( 0, 0, width, height);
|
---|
1226 | glMatrixMode( GL_PROJECTION );
|
---|
1227 | glLoadIdentity();
|
---|
1228 | glOrtho( 0, width - 1, 0, height - 1, 1, -1 ); // aargh...
|
---|
1229 | glMatrixMode( GL_MODELVIEW );
|
---|
1230 | glLoadIdentity();
|
---|
1231 | }
|
---|
1232 |
|
---|
1233 | void OpenglVideo::InitOpengl(void)
|
---|
1234 | {
|
---|
1235 | gl->MakeCurrent(true);
|
---|
1236 | glDisable( GL_BLEND );
|
---|
1237 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // for gl osd
|
---|
1238 | glDisable( GL_DEPTH_TEST );
|
---|
1239 | glDepthMask( GL_FALSE );
|
---|
1240 | glDisable( GL_CULL_FACE );
|
---|
1241 | gl->EnableTextures();;
|
---|
1242 | glShadeModel( GL_FLAT );
|
---|
1243 | glDisable( GL_POLYGON_SMOOTH );
|
---|
1244 | glDisable( GL_LINE_SMOOTH );
|
---|
1245 | glDisable( GL_POINT_SMOOTH );
|
---|
1246 | glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
|
---|
1247 | glClear( GL_COLOR_BUFFER_BIT );
|
---|
1248 | glFlush();
|
---|
1249 | gl->MakeCurrent(false);
|
---|
1250 | }
|
---|
1251 |
|
---|
1252 | GLuint OpenglVideo::CreateVideoTexture(QSize size, QSize *tex_size, bool YUV12)
|
---|
1253 | {
|
---|
1254 | GLuint tmp_tex;
|
---|
1255 | QSize temp = size;
|
---|
1256 | gl->CreateTexture(&tmp_tex);
|
---|
1257 | GetTextureSize(&temp, size);
|
---|
1258 | if (YUV12)
|
---|
1259 | {
|
---|
1260 | if (gl->TextureSupport())
|
---|
1261 | {
|
---|
1262 | temp.rheight() = size.height() * 3 / 2;
|
---|
1263 | }
|
---|
1264 | else
|
---|
1265 | {
|
---|
1266 | if ((size.height() * 1.5) > temp.height())
|
---|
1267 | temp.rheight() *= 2;
|
---|
1268 | }
|
---|
1269 | }
|
---|
1270 | if (temp.width() > gl->GetMaxTexSize() ||
|
---|
1271 | temp.height() > gl->GetMaxTexSize() ||
|
---|
1272 | !gl->SetupTexture(temp, &tmp_tex, GL_LINEAR))
|
---|
1273 | {
|
---|
1274 | VERBOSE(VB_PLAYBACK, LOC_ERR + "Could not create texture.");
|
---|
1275 | gl->DeleteTexture(&tmp_tex);
|
---|
1276 | return 0;
|
---|
1277 | }
|
---|
1278 |
|
---|
1279 | tex_size->setWidth(temp.width());
|
---|
1280 | tex_size->setHeight(temp.height());
|
---|
1281 | VERBOSE(VB_PLAYBACK, LOC + QString("Created main input texture %1x%2")
|
---|
1282 | .arg(temp.width()).arg(temp.height()));
|
---|
1283 | return tmp_tex;
|
---|
1284 | }
|
---|
1285 |
|
---|
1286 | void OpenglVideo::GetTextureSize(QSize *temp, QSize size)
|
---|
1287 | {
|
---|
1288 | if (gl->TextureSupport())
|
---|
1289 | return; glOrtho( 0, width, 0, height, 1, -1 ); // aargh...
|
---|
1290 | int w, h;
|
---|
1291 | w = h = 64;
|
---|
1292 | while (w < size.width()) { w *= 2; }
|
---|
1293 | while (h < size.height()) { h *= 2; }
|
---|
1294 | temp->setWidth(w);
|
---|
1295 | temp->setHeight(h);
|
---|
1296 | }
|
---|
1297 |
|
---|
1298 | void OpenglVideo::UpdateInputFrame(VideoFrame *frame)
|
---|
1299 | {
|
---|
1300 | bool errored = false;
|
---|
1301 | if (frame->width != videoSize.width() ||
|
---|
1302 | frame->height != videoSize.height() ||
|
---|
1303 | frame->width < 1 ||
|
---|
1304 | frame->height < 1)
|
---|
1305 | errored = true;
|
---|
1306 |
|
---|
1307 | if (filters.count(kYUV2RGB) && !errored && frame->codec == FMT_YV12)
|
---|
1308 | UpdateInput(frame->buf, 0, FMT_YV12, videoSize);
|
---|
1309 | else // software yuv2rgb
|
---|
1310 | {
|
---|
1311 | if (errored)
|
---|
1312 | {
|
---|
1313 | ShutDownYUV2RGB();
|
---|
1314 | return;
|
---|
1315 | }
|
---|
1316 | if (convertSize != videoSize)
|
---|
1317 | {
|
---|
1318 | ShutDownYUV2RGB();
|
---|
1319 | VERBOSE(VB_PLAYBACK, LOC + "Init software conversion.");
|
---|
1320 | convertSize = videoSize;
|
---|
1321 | convertBuf = new unsigned char[(videoSize.width() *
|
---|
1322 | videoSize.height() * 3) + 4];
|
---|
1323 | }
|
---|
1324 | if (convertBuf)
|
---|
1325 | {
|
---|
1326 | AVPicture img_in, img_out;
|
---|
1327 | avpicture_fill(&img_out, (uint8_t *)convertBuf, PIX_FMT_RGB24,
|
---|
1328 | convertSize.width(), convertSize.height());
|
---|
1329 | avpicture_fill(&img_in, (uint8_t *)frame->buf, PIX_FMT_YUV420P,
|
---|
1330 | convertSize.width(), convertSize.height());
|
---|
1331 | img_convert(&img_out, PIX_FMT_RGB24,
|
---|
1332 | &img_in, PIX_FMT_YUV420P,
|
---|
1333 | convertSize.width(), convertSize.height());
|
---|
1334 | UpdateInput(convertBuf, 0, FMT_RGB24, convertSize);
|
---|
1335 | }
|
---|
1336 | }
|
---|
1337 | }
|
---|
1338 |
|
---|
1339 | void OpenglVideo::UpdateInput(unsigned char *buf, uint texture,
|
---|
1340 | int format, QSize size)
|
---|
1341 | {
|
---|
1342 | inputUpdated = false;
|
---|
1343 | if (texture > (inputTextures.size() - 1))
|
---|
1344 | return;
|
---|
1345 |
|
---|
1346 | glBindTexture( gl->m_texture, inputTextures[texture] );
|
---|
1347 | switch (format)
|
---|
1348 | {
|
---|
1349 | case FMT_YV12:
|
---|
1350 | glTexSubImage2D( gl->m_texture, 0, 0, 0,
|
---|
1351 | size.width(), size.height(),
|
---|
1352 | GL_LUMINANCE, GL_UNSIGNED_BYTE, buf);
|
---|
1353 | glTexSubImage2D( gl->m_texture, 0, 0, size.height() ,
|
---|
1354 | size.width() / 2, size.height() / 2,
|
---|
1355 | GL_LUMINANCE, GL_UNSIGNED_BYTE,
|
---|
1356 | buf + (size.width() * size.height()));
|
---|
1357 | glTexSubImage2D( gl->m_texture, 0, size.width() / 2,
|
---|
1358 | size.height() , size.width() / 2,
|
---|
1359 | size.height() / 2, GL_LUMINANCE,
|
---|
1360 | GL_UNSIGNED_BYTE,buf + (size.width()
|
---|
1361 | * size.height()) * 5 / 4);
|
---|
1362 | break;
|
---|
1363 | case FMT_RGB24:
|
---|
1364 | glTexSubImage2D( gl->m_texture, 0, 0, 0,
|
---|
1365 | size.width(), size.height(),
|
---|
1366 | GL_RGB, GL_UNSIGNED_BYTE, buf);
|
---|
1367 | break;
|
---|
1368 | case FMT_ALPHA:
|
---|
1369 | glTexSubImage2D( gl->m_texture, 0, 0, 0,
|
---|
1370 | size.width(), size.height(),
|
---|
1371 | GL_ALPHA, GL_UNSIGNED_BYTE,
|
---|
1372 | buf);
|
---|
1373 | break;
|
---|
1374 | default:
|
---|
1375 | break;
|
---|
1376 | }
|
---|
1377 | inputUpdated = true;
|
---|
1378 | }
|
---|
1379 |
|
---|
1380 | void OpenglVideo::ShutDownYUV2RGB(void)
|
---|
1381 | {
|
---|
1382 | if (convertBuf)
|
---|
1383 | {
|
---|
1384 | delete convertBuf;
|
---|
1385 | convertBuf = NULL;
|
---|
1386 | }
|
---|
1387 | convertSize = QSize(0,0);
|
---|
1388 | }
|
---|
1389 |
|
---|
1390 | void OpenglVideo::SetVideoResize(QRect *size)
|
---|
1391 | {
|
---|
1392 | if (!size || size == NULL)
|
---|
1393 | {
|
---|
1394 | videoResize = false;
|
---|
1395 | videoResizeRect = QRect(0, 0, 0, 0);
|
---|
1396 | return;
|
---|
1397 | }
|
---|
1398 |
|
---|
1399 | bool abort = (size->right() > videoSize.width() ||
|
---|
1400 | size->bottom() > videoSize.height() ||
|
---|
1401 | size->width() > videoSize.width() ||
|
---|
1402 | size->height() > videoSize.height());
|
---|
1403 | // if resize == existing frame, no need to carry on
|
---|
1404 | abort |= !size->left() && !size->top() && (size->size() == videoSize);
|
---|
1405 |
|
---|
1406 | if (abort)
|
---|
1407 | {
|
---|
1408 | videoResize = false;
|
---|
1409 | videoResizeRect = QRect(0, 0, 0, 0);
|
---|
1410 | return;
|
---|
1411 | }
|
---|
1412 |
|
---|
1413 | videoResize = true;
|
---|
1414 | videoResizeRect = *size;
|
---|
1415 | }
|
---|
1416 |
|
---|
1417 | void OpenglVideo::CalculateResize(float *left, float *top,
|
---|
1418 | float *right, float *bottom)
|
---|
1419 | {
|
---|
1420 | // FIXME video aspect == display aspect
|
---|
1421 | float height = visibleRect.height();
|
---|
1422 | float new_top = height - ((float)videoResizeRect.bottom() /
|
---|
1423 | (float)videoSize.height()) * height;
|
---|
1424 | float new_bottom = height - ((float)videoResizeRect.top() /
|
---|
1425 | (float)videoSize.height()) * height;
|
---|
1426 | *left = ((float)videoResizeRect.left() / (float)videoSize.width()) *
|
---|
1427 | visibleRect.width();
|
---|
1428 | *right = ((float)videoResizeRect.right() / (float)videoSize.width()) *
|
---|
1429 | visibleRect.width();
|
---|
1430 | *top = new_top;
|
---|
1431 | *bottom = new_bottom;
|
---|
1432 | }
|
---|
1433 |
|
---|
1434 | void OpenglVideo::SetDeinterlacing(bool deinterlacing)
|
---|
1435 | {
|
---|
1436 | if (deinterlacing == hardwareDeinterlacing)
|
---|
1437 | return;
|
---|
1438 | VERBOSE(VB_PLAYBACK, LOC + QString("Turning %1 deinterlacing.")
|
---|
1439 | .arg(deinterlacing ? "on" : "off"));
|
---|
1440 | hardwareDeinterlacing = deinterlacing;
|
---|
1441 | map<OpenglFilter, Filter>::iterator it;
|
---|
1442 | for (it = filters.begin(); it !=filters.end(); it++)
|
---|
1443 | {
|
---|
1444 | it->second.outputBuffer = kFrameBufferObject;
|
---|
1445 | if (it->first >= kKDEINT && it->first <= kPROGONEFIELD)
|
---|
1446 | {
|
---|
1447 | if (!deinterlacing)
|
---|
1448 | it->second.outputBuffer = kNoBuffer;
|
---|
1449 | }
|
---|
1450 | }
|
---|
1451 | map<OpenglFilter, Filter>::reverse_iterator rit;
|
---|
1452 | for (rit = filters.rbegin(); rit !=filters.rend(); rit++)
|
---|
1453 | {
|
---|
1454 | if (rit->second.outputBuffer == kFrameBufferObject)
|
---|
1455 | {
|
---|
1456 | rit->second.outputBuffer = kDefaultBuffer;
|
---|
1457 | break;
|
---|
1458 | }
|
---|
1459 | }
|
---|
1460 | gl->MakeCurrent(true);
|
---|
1461 | SetFiltering();
|
---|
1462 | gl->MakeCurrent(false);
|
---|
1463 | }
|
---|
1464 |
|
---|
1465 | void OpenglVideo::Show(FrameScanType scan, bool softwareDeinterlacing,
|
---|
1466 | long long frame)
|
---|
1467 | {
|
---|
1468 | if (inputTextures.empty() || filters.empty())
|
---|
1469 | return;
|
---|
1470 |
|
---|
1471 | vector<GLuint> inputs = inputTextures;
|
---|
1472 | QSize inputsize = inputTextureSize;
|
---|
1473 | uint numfilters = filters.size();
|
---|
1474 |
|
---|
1475 | map<OpenglFilter, Filter>::iterator it;
|
---|
1476 | for (it = filters.begin(); it !=filters.end(); it++)
|
---|
1477 | {
|
---|
1478 | if (it->second.rotateFrameBuffers &&
|
---|
1479 | !(it->first == kYUV2RGB && scan == kScan_Intr2ndField))
|
---|
1480 | {
|
---|
1481 | Rotate(&(it->second.frameBufferTextures));
|
---|
1482 | Rotate(&(it->second.frameBuffers));
|
---|
1483 | }
|
---|
1484 |
|
---|
1485 | // skip disabled filters
|
---|
1486 | if (it->second.outputBuffer == kNoBuffer)
|
---|
1487 | continue;
|
---|
1488 |
|
---|
1489 | OpenglFilter type = it->first;
|
---|
1490 | Filter filter = it->second;
|
---|
1491 |
|
---|
1492 | // skip colour conversion for frames already in frame buffer
|
---|
1493 | if (!inputUpdated)
|
---|
1494 | if (frame == currentFrameNum && type == kYUV2RGB && frame != 0)
|
---|
1495 | if (!(softwareDeinterlacing &&
|
---|
1496 | softwareDeinterlacer == "bobdeint"))
|
---|
1497 | {
|
---|
1498 | inputs = filter.frameBufferTextures;
|
---|
1499 | inputsize = videoSize;
|
---|
1500 | continue;
|
---|
1501 | }
|
---|
1502 |
|
---|
1503 | // texture coordinates
|
---|
1504 | float t_right = (float)videoSize.width();
|
---|
1505 | float t_bottom = (float)videoSize.height();
|
---|
1506 | float t_top = 0.0f;
|
---|
1507 |
|
---|
1508 | if (!gl->TextureSupport())
|
---|
1509 | {
|
---|
1510 | t_right /= inputsize.width();
|
---|
1511 | t_bottom /= inputsize.height();
|
---|
1512 | }
|
---|
1513 |
|
---|
1514 | float full_height = t_bottom;
|
---|
1515 | float line_height = (t_bottom / (float)videoSize.height());
|
---|
1516 | float bob = line_height / 2.0f;
|
---|
1517 |
|
---|
1518 | if (type == kBOBDEINT)
|
---|
1519 | {
|
---|
1520 | if (scan == kScan_Interlaced)
|
---|
1521 | {
|
---|
1522 | t_bottom += bob;
|
---|
1523 | t_top += bob;
|
---|
1524 | }
|
---|
1525 | if (scan == kScan_Intr2ndField)
|
---|
1526 | {
|
---|
1527 | t_bottom -= bob;
|
---|
1528 | t_top -= bob;
|
---|
1529 | }
|
---|
1530 | }
|
---|
1531 | if (softwareDeinterlacer == "bobdeint" &&
|
---|
1532 | softwareDeinterlacing &&
|
---|
1533 | type == kYUV2RGB)
|
---|
1534 | {
|
---|
1535 | bob = line_height / 4.0f;
|
---|
1536 | if (scan == kScan_Interlaced)
|
---|
1537 | {
|
---|
1538 | t_bottom /= 2;
|
---|
1539 | t_bottom += bob;
|
---|
1540 | t_top += bob;
|
---|
1541 | }
|
---|
1542 | if (scan == kScan_Intr2ndField)
|
---|
1543 | {
|
---|
1544 | t_top = t_bottom / 2;
|
---|
1545 | t_bottom -= bob;
|
---|
1546 | t_top -= bob;
|
---|
1547 | }
|
---|
1548 | }
|
---|
1549 |
|
---|
1550 | // vertex coordinates
|
---|
1551 | QRect display;
|
---|
1552 | if (filter.outputBuffer == kDefaultBuffer)
|
---|
1553 | display = videoRect;
|
---|
1554 | else
|
---|
1555 | display = frameBufferRect;
|
---|
1556 |
|
---|
1557 | float vleft = display.left();
|
---|
1558 | float vright = display.right();
|
---|
1559 | float vtop = display.top();
|
---|
1560 | float vbot = display.bottom();
|
---|
1561 |
|
---|
1562 | // resize for interactive tv
|
---|
1563 | if (videoResize && filter.outputBuffer == kDefaultBuffer)
|
---|
1564 | CalculateResize(&vleft, &vtop, &vright, &vbot);
|
---|
1565 |
|
---|
1566 | if (invertVideo && (type == kYUV2RGB || type == kYUV2RGBA)
|
---|
1567 | || (type == kRESIZE && numfilters == 1))
|
---|
1568 | {
|
---|
1569 | float temp = vtop;
|
---|
1570 | vtop = vbot;
|
---|
1571 | vbot = temp;
|
---|
1572 | }
|
---|
1573 |
|
---|
1574 | // bind correct frame buffer (default onscreen) and set viewport
|
---|
1575 | switch (filter.outputBuffer)
|
---|
1576 | {
|
---|
1577 | case kDefaultBuffer:
|
---|
1578 | if (frameBuffer)
|
---|
1579 | gl->m_glBindFramebufferEXT( GL_FRAMEBUFFER_EXT,
|
---|
1580 | frameBuffer);
|
---|
1581 | // clear the buffer
|
---|
1582 | if (viewportControl)
|
---|
1583 | {
|
---|
1584 | glClear(GL_COLOR_BUFFER_BIT);
|
---|
1585 | ViewPort(visibleRect.width(), visibleRect.height());
|
---|
1586 | }
|
---|
1587 | else
|
---|
1588 | ViewPort(masterViewportSize.width(),
|
---|
1589 | masterViewportSize.height());
|
---|
1590 | break;
|
---|
1591 | case kFrameBufferObject:
|
---|
1592 | gl->m_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,
|
---|
1593 | filter.frameBuffers[0] );
|
---|
1594 | ViewPort(frameBufferRect.width(), frameBufferRect.height());
|
---|
1595 | break;
|
---|
1596 | case kNoBuffer:
|
---|
1597 | continue;
|
---|
1598 | }
|
---|
1599 |
|
---|
1600 | // bind correct textures
|
---|
1601 | for (uint i = 0; i < inputs.size(); i++)
|
---|
1602 | {
|
---|
1603 | glActiveTexture( GL_TEXTURE0 + i );
|
---|
1604 | glBindTexture( gl->m_texture, inputs[i] );
|
---|
1605 | }
|
---|
1606 |
|
---|
1607 | // enable fragment program and set any environment variables
|
---|
1608 | if (!(type == kNOFILT || type == kRESIZE))
|
---|
1609 | {
|
---|
1610 | glEnable ( GL_FRAGMENT_PROGRAM_ARB );
|
---|
1611 | gl->m_glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB,
|
---|
1612 | filter.fragmentProgram );
|
---|
1613 | float field = -line_height;
|
---|
1614 | switch (type)
|
---|
1615 | {
|
---|
1616 | case kYUV2RGB:
|
---|
1617 | case kYUV2RGBA:
|
---|
1618 | gl->m_glProgramEnvParameter4fARB (GL_FRAGMENT_PROGRAM_ARB,
|
---|
1619 | 1, t_right / 2.0f, full_height, 0.0f, 0.0f);
|
---|
1620 | if (useColourControl)
|
---|
1621 | gl->m_glProgramEnvParameter4fARB(
|
---|
1622 | GL_FRAGMENT_PROGRAM_ARB, 0,
|
---|
1623 | (pictureAttribs[kPictureAttribute_Brightness] / 50 ) - 0.5,
|
---|
1624 | (pictureAttribs[kPictureAttribute_Contrast] / 50),
|
---|
1625 | (pictureAttribs[kPictureAttribute_Colour] / 50),
|
---|
1626 | 0.0f);
|
---|
1627 | break;
|
---|
1628 | case kBOBDEINT:
|
---|
1629 | case kPROGONEFIELD:
|
---|
1630 | case kPROGKDEINT:
|
---|
1631 | case kPROGLINBLEND:
|
---|
1632 | if (scan == kScan_Intr2ndField)
|
---|
1633 | field *= -1;
|
---|
1634 | case kONEFIELD:
|
---|
1635 | case kKDEINT:
|
---|
1636 | case kLINBLEND:
|
---|
1637 | gl->m_glProgramEnvParameter4fARB ( GL_FRAGMENT_PROGRAM_ARB,
|
---|
1638 | 0, line_height * 2, field, 0.0f, 0.0f);
|
---|
1639 | break;
|
---|
1640 | case kNOFILT:
|
---|
1641 | case kRESIZE:
|
---|
1642 | break;
|
---|
1643 | }
|
---|
1644 | }
|
---|
1645 |
|
---|
1646 | // enable blending for osd
|
---|
1647 | if (type == kYUV2RGBA)
|
---|
1648 | glEnable(GL_BLEND);
|
---|
1649 |
|
---|
1650 | // draw quad
|
---|
1651 | glBegin( GL_QUADS );
|
---|
1652 | glTexCoord2f(0.0f, t_top); glVertex2f(vleft, vtop);
|
---|
1653 | glTexCoord2f(t_right, t_top); glVertex2f(vright, vtop);
|
---|
1654 | glTexCoord2f(t_right, t_bottom); glVertex2f(vright, vbot);
|
---|
1655 | glTexCoord2f(0.0f, t_bottom); glVertex2f(vleft, vbot);
|
---|
1656 | glEnd();
|
---|
1657 |
|
---|
1658 | // disable blending
|
---|
1659 | if (type == kYUV2RGBA)
|
---|
1660 | glDisable(GL_BLEND);
|
---|
1661 |
|
---|
1662 | // disable fragment program
|
---|
1663 | if (!(type == kNOFILT || type == kRESIZE))
|
---|
1664 | {
|
---|
1665 | gl->m_glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, 0 );
|
---|
1666 | glDisable ( GL_FRAGMENT_PROGRAM_ARB );
|
---|
1667 | }
|
---|
1668 |
|
---|
1669 | // switch back to default framebuffer
|
---|
1670 | if (filter.outputBuffer != kDefaultBuffer || frameBuffer)
|
---|
1671 | gl->m_glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
|
---|
1672 |
|
---|
1673 | inputs = filter.frameBufferTextures;
|
---|
1674 | inputsize = videoSize;
|
---|
1675 | }
|
---|
1676 | currentFrameNum = frame;
|
---|
1677 | inputUpdated = false;
|
---|
1678 | }
|
---|
1679 |
|
---|
1680 | void OpenglVideo::Rotate(vector<GLuint> *target)
|
---|
1681 | {
|
---|
1682 | if (target->size() < 2)
|
---|
1683 | return;
|
---|
1684 | GLuint tmp = (*target)[target->size() - 1];
|
---|
1685 | for (uint i = target->size() - 1; i > 0; i--)
|
---|
1686 | (*target)[i] = (*target)[i-1];
|
---|
1687 | (*target)[0] = tmp;
|
---|
1688 | }
|
---|
1689 |
|
---|
1690 | void OpenglVideo::SetPictureAttribute(int attributeType, int newValue)
|
---|
1691 | {
|
---|
1692 | pictureAttribs[attributeType] = (float) newValue;
|
---|
1693 | }
|
---|
1694 |
|
---|
1695 | void OpenglVideo::SetTextureFilters(vector<GLuint> *textures, int filt)
|
---|
1696 | {
|
---|
1697 | if (textures->empty())
|
---|
1698 | return;
|
---|
1699 | for (uint i = 0; i < textures->size(); i++)
|
---|
1700 | gl->SetupTextureFilters(&((*textures)[i]), filt);
|
---|
1701 | }
|
---|
1702 |
|
---|
1703 | OpenglFilter OpenglVideo::StringToFilter(QString filter)
|
---|
1704 | {
|
---|
1705 | OpenglFilter ret = kNOFILT;
|
---|
1706 | if (filter.contains("master"))
|
---|
1707 | ret = kYUV2RGB;
|
---|
1708 | else if (filter.contains("osd"))
|
---|
1709 | ret = kYUV2RGBA;
|
---|
1710 | else if (filter.contains("openglkerneldeint"))
|
---|
1711 | ret = kKDEINT;
|
---|
1712 | else if (filter.contains("opengllinearblend"))
|
---|
1713 | ret = kLINBLEND;
|
---|
1714 | else if (filter.contains("openglonefield"))
|
---|
1715 | ret = kONEFIELD;
|
---|
1716 | else if (filter.contains("openglbobdeint"))
|
---|
1717 | ret = kBOBDEINT;
|
---|
1718 | else if (filter.contains("openglprogressivelinearblend"))
|
---|
1719 | ret = kPROGLINBLEND;
|
---|
1720 | else if (filter.contains("openglprogressivekerneldeint"))
|
---|
1721 | ret = kPROGKDEINT;
|
---|
1722 | else if (filter.contains("openglprogressiveonefield"))
|
---|
1723 | ret = kPROGONEFIELD;
|
---|
1724 | else if (filter.contains("resize"))
|
---|
1725 | ret = kRESIZE;
|
---|
1726 | return ret;
|
---|
1727 | }
|
---|
1728 |
|
---|
1729 | QString OpenglVideo::FilterToString(OpenglFilter filt)
|
---|
1730 | {
|
---|
1731 | switch (filt)
|
---|
1732 | {
|
---|
1733 | case kNOFILT:
|
---|
1734 | break;
|
---|
1735 | case kYUV2RGB:
|
---|
1736 | return "master";
|
---|
1737 | case kYUV2RGBA:
|
---|
1738 | return "osd";
|
---|
1739 | case kKDEINT:
|
---|
1740 | return "openglkerneldeint";
|
---|
1741 | case kLINBLEND:
|
---|
1742 | return "opengllinearblend";
|
---|
1743 | case kONEFIELD:
|
---|
1744 | return "openglonefield";
|
---|
1745 | case kBOBDEINT:
|
---|
1746 | return "openglbobdeint";
|
---|
1747 | case kPROGLINBLEND:
|
---|
1748 | return "openglprogressivelinearblend";
|
---|
1749 | case kPROGKDEINT:
|
---|
1750 | return "openglprogressivekerneldeint";
|
---|
1751 | case kPROGONEFIELD:
|
---|
1752 | return "openglprogressiveonefield";
|
---|
1753 | case kRESIZE:
|
---|
1754 | return "resize";
|
---|
1755 | }
|
---|
1756 | return "";
|
---|
1757 | }
|
---|
1758 |
|
---|
1759 | static const QString yuv2rgb1a =
|
---|
1760 | "ATTRIB ytex = fragment.texcoord[0];"
|
---|
1761 | "PARAM off = program.env[1];"
|
---|
1762 | "TEMP res, tmp, tmp2;";
|
---|
1763 |
|
---|
1764 | static const QString yuv2rgb1b =
|
---|
1765 | "TEMP alpha;"
|
---|
1766 | "TEX alpha, ytex, texture[1], %1;";
|
---|
1767 |
|
---|
1768 | static const QString yuv2rgb1c =
|
---|
1769 | "TEX res, ytex, texture[0], %1;"
|
---|
1770 | "MAD tmp2, ytex, {0.5, 0.5}, off.wyww;"
|
---|
1771 | "TEX tmp.x, tmp2, texture[0], %1;"
|
---|
1772 | "ADD tmp2, tmp2, off.xwww;"
|
---|
1773 | "TEX tmp.y, tmp2, texture[0], %1;";
|
---|
1774 |
|
---|
1775 | static const QString yuv2rgb2 =
|
---|
1776 | "PARAM adj = program.env[0];"
|
---|
1777 | "SUB res, res, 0.5;"
|
---|
1778 | "MAD res, res, adj.yyyy, adj.xxxx;"
|
---|
1779 | "SUB tmp, tmp, { 0.5, 0.5 };"
|
---|
1780 | "MAD tmp, adj.zzzz, tmp, 0.5;";
|
---|
1781 |
|
---|
1782 | static const QString yuv2rgb3 =
|
---|
1783 | "MAD res, res, 1.164, -0.063;"
|
---|
1784 | "SUB tmp, tmp, { 0.5, 0.5 };"
|
---|
1785 | "MAD res, { 0, -.392, 2.017 }, tmp.xxxw, res;";
|
---|
1786 |
|
---|
1787 | static const QString yuv2rgb4 =
|
---|
1788 | "MAD result.color, { 1.596, -.813, 0, 0 }, tmp.yyyw, res;";
|
---|
1789 |
|
---|
1790 | static const QString yuv2rgb5 =
|
---|
1791 | "MAD result.color, { 0, -.813, 1.596, 0 }, tmp.yyyw, res.bgra;";
|
---|
1792 |
|
---|
1793 | static const QString yuv2rgb6 =
|
---|
1794 | "MOV result.color.a, alpha.a;";
|
---|
1795 |
|
---|
1796 |
|
---|
1797 | QString OpenglVideo::GetProgramString(OpenglFilter name)
|
---|
1798 | {
|
---|
1799 | QString ret =
|
---|
1800 | "!!ARBfp1.0\n"
|
---|
1801 | "OPTION ARB_precision_hint_fastest;";
|
---|
1802 | switch (name)
|
---|
1803 | {
|
---|
1804 | case kYUV2RGB:
|
---|
1805 | ret = ret + yuv2rgb1a + yuv2rgb1c;
|
---|
1806 | if (useColourControl)
|
---|
1807 | ret += yuv2rgb2;
|
---|
1808 | ret += yuv2rgb3;
|
---|
1809 | ret += frameBuffer ? yuv2rgb5 : yuv2rgb4;
|
---|
1810 | break;
|
---|
1811 | case kYUV2RGBA:
|
---|
1812 | ret = ret + yuv2rgb1a + yuv2rgb1b + yuv2rgb1c;
|
---|
1813 | if (useColourControl)
|
---|
1814 | ret += yuv2rgb2;
|
---|
1815 | ret = ret + yuv2rgb3 + yuv2rgb4 + yuv2rgb6;
|
---|
1816 | break;
|
---|
1817 | case kKDEINT:
|
---|
1818 | ret +=
|
---|
1819 | "ATTRIB tex = fragment.texcoord[0];"
|
---|
1820 | "PARAM off = program.env[0];"
|
---|
1821 | "TEMP sam, pos, cum, cur, field, mov;"
|
---|
1822 | "RCP field, off.x;"
|
---|
1823 | "MUL field, tex.yyyy, field;"
|
---|
1824 | "FRC field, field;"
|
---|
1825 | "SUB field, field, 0.5;"
|
---|
1826 | "TEX sam, tex, texture[1], %1;"
|
---|
1827 | "TEX cur, tex, texture[0], %1;"
|
---|
1828 | "SUB mov, cur, sam;"
|
---|
1829 | "MUL cum, sam, 0.125;"
|
---|
1830 | "MAD cum, cur, 0.125, cum;"
|
---|
1831 | "ABS mov, mov;"
|
---|
1832 | "SUB mov, mov, 0.12;"
|
---|
1833 | "ADD pos, tex, off.wyww;"
|
---|
1834 | "TEX sam, pos, texture[0], %1;"
|
---|
1835 | "MAD cum, sam, 0.5, cum;"
|
---|
1836 | "SUB pos, tex, off.wyww;"
|
---|
1837 | "TEX sam, pos, texture[0], %1;"
|
---|
1838 | "MAD cum, sam, 0.5, cum;"
|
---|
1839 | "MAD pos, off.wyww, 2.0, tex;"
|
---|
1840 | "TEX sam, pos, texture[0], %1;"
|
---|
1841 | "MAD cum, sam, -0.0625, cum;"
|
---|
1842 | "TEX sam, pos, texture[1], %1;"
|
---|
1843 | "MAD cum, sam, -0.0625, cum;"
|
---|
1844 | "MAD pos, off.wyww, -2.0, tex;"
|
---|
1845 | "TEX sam, pos, texture[0], %1;"
|
---|
1846 | "MAD cum, sam, -0.0625, cum;"
|
---|
1847 | "TEX sam, pos, texture[1], %1;"
|
---|
1848 | "MAD cum, sam, -0.0625, cum;"
|
---|
1849 | "CMP cum, mov, cur, cum;"
|
---|
1850 | "CMP result.color, field, cum, cur;";
|
---|
1851 | break;
|
---|
1852 | case kPROGLINBLEND:
|
---|
1853 | ret +=
|
---|
1854 | "ATTRIB tex = fragment.texcoord[0];"
|
---|
1855 | "PARAM off = program.env[0];"
|
---|
1856 | "TEMP field, top, bot, current, previous, next, other, mov;"
|
---|
1857 | "TEX next, tex, texture[0], %1;"
|
---|
1858 | "TEX current, tex, texture[1], %1;"
|
---|
1859 | "TEX previous, tex, texture[2], %1;"
|
---|
1860 | "ADD top, tex, off.wyww;"
|
---|
1861 | "TEX other, top, texture[1], %1;"
|
---|
1862 | "SUB top, tex, off.wyww;"
|
---|
1863 | "TEX bot, top, texture[1], %1;"
|
---|
1864 | "LRP other, 0.5, other, bot;"
|
---|
1865 | "RCP field, off.x;"
|
---|
1866 | "MUL field, tex.yyyy, field;"
|
---|
1867 | "FRC field, field;"
|
---|
1868 | "SUB field, field, 0.5;"
|
---|
1869 | "SUB top, current, next;"
|
---|
1870 | "SUB bot, current, previous;"
|
---|
1871 | "CMP mov, field, bot, top;"
|
---|
1872 | "ABS mov, mov;"
|
---|
1873 | "SUB mov, mov, 0.12;"
|
---|
1874 | "CMP other, mov, current, other;"
|
---|
1875 | "CMP top, field, other, current;"
|
---|
1876 | "CMP bot, field, current, other;"
|
---|
1877 | "CMP result.color, off.y, top, bot;";
|
---|
1878 | break;
|
---|
1879 | case kPROGONEFIELD:
|
---|
1880 | ret +=
|
---|
1881 | "ATTRIB tex = fragment.texcoord[0];"
|
---|
1882 | "PARAM off = program.env[0];"
|
---|
1883 | "TEMP field, top, bot, current, previous, next, other, mov;"
|
---|
1884 | "TEX next, tex, texture[0], %1;"
|
---|
1885 | "TEX current, tex, texture[1], %1;"
|
---|
1886 | "TEX previous, tex, texture[2], %1;"
|
---|
1887 | "ADD top, tex, off.wyww;"
|
---|
1888 | "TEX other, top, texture[1], %1;"
|
---|
1889 | "RCP field, off.x;"
|
---|
1890 | "MUL field, tex.yyyy, field;"
|
---|
1891 | "FRC field, field;"
|
---|
1892 | "SUB field, field, 0.5;"
|
---|
1893 | "SUB top, current, next;"
|
---|
1894 | "SUB bot, current, previous;"
|
---|
1895 | "CMP mov, field, bot, top;"
|
---|
1896 | "ABS mov, mov;"
|
---|
1897 | "SUB mov, mov, 0.12;"
|
---|
1898 | "CMP other, mov, current, other;"
|
---|
1899 | "CMP top, field, other, current;"
|
---|
1900 | "CMP bot, field, current, other;"
|
---|
1901 | "CMP result.color, off.y, top, bot;";
|
---|
1902 | break;
|
---|
1903 | case kPROGKDEINT:
|
---|
1904 | ret +=
|
---|
1905 | "ATTRIB tex = fragment.texcoord[0];"
|
---|
1906 | "PARAM off = program.env[0];"
|
---|
1907 | "TEMP sam, pos, bot, top, cur, pre, nex, field, mov;"
|
---|
1908 | "RCP field, off.x;"
|
---|
1909 | "MUL field, tex.yyyy, field;"
|
---|
1910 | "FRC field, field;"
|
---|
1911 | "SUB field, field, 0.5;"
|
---|
1912 | "TEX pre, tex, texture[2], %1;" // -1,0
|
---|
1913 | "TEX cur, tex, texture[1], %1;" // 0,0
|
---|
1914 | "TEX nex, tex, texture[0], %1;" // +1,0
|
---|
1915 | "SUB top, nex, cur;"
|
---|
1916 | "SUB bot, pre, cur;"
|
---|
1917 | "CMP mov, field, bot, top;"
|
---|
1918 | "ABS mov, mov;"
|
---|
1919 | "SUB mov, mov, 0.12;"
|
---|
1920 | "MUL bot, pre, 0.125;" // BOT -1,0
|
---|
1921 | "MAD bot, cur, 0.125, bot;" // BOT +1,0
|
---|
1922 | "MUL top, cur, 0.125;" // TOP -1,0
|
---|
1923 | "MAD top, nex, 0.125, top;" // TOP +1,0
|
---|
1924 | "ADD pos, tex, off.wyww;"
|
---|
1925 | "TEX sam, pos, texture[1], %1;" // 0,+1
|
---|
1926 | "MAD bot, sam, 0.5, bot;" // BOT 0,+1
|
---|
1927 | "MAD top, sam, 0.5, top;" // TOP 0,+1
|
---|
1928 | "SUB pos, tex, off.wyww;"
|
---|
1929 | "TEX sam, pos, texture[1], %1;" // 0,-1
|
---|
1930 | "MAD bot, sam, 0.5, bot;" // BOT 0,-1
|
---|
1931 | "MAD top, sam, 0.5, top;" // TOP 0,-1
|
---|
1932 | "MAD pos, off.wyww, 2.0, tex;"
|
---|
1933 | "TEX sam, pos, texture[1], %1;" // 0,+2
|
---|
1934 | "MAD bot, sam, -0.0625, bot;" // BOT +1,+2
|
---|
1935 | "MAD top, sam, -0.0625, top;" // TOP -1,+2
|
---|
1936 | "TEX sam, pos, texture[2], %1;" // -1,+2
|
---|
1937 | "MAD bot, sam, -0.0625, bot;" // BOT -1,+2
|
---|
1938 | "TEX sam, pos, texture[0], %1;" // +1,+2
|
---|
1939 | "MAD top, sam, -0.0625, top;" // TOP +1,+2
|
---|
1940 | "MAD pos, off.wyww, -2.0, tex;"
|
---|
1941 | "TEX sam, pos, texture[1], %1;" // +1,-2
|
---|
1942 | "MAD bot, sam, -0.0625, bot;" // BOT +1,-2
|
---|
1943 | "MAD top, sam, -0.0625, top;" // TOP -1,-2
|
---|
1944 | "TEX sam, pos, texture[2], %1;" // -1, -2 row
|
---|
1945 | "MAD bot, sam, -0.0625, bot;" // BOT -1,-2
|
---|
1946 | "TEX sam, pos, texture[0], %1;" // +1,-2
|
---|
1947 | "MAD top, sam, -0.0625, top;" // TOP +1,-2
|
---|
1948 | "CMP top, mov, cur, top;"
|
---|
1949 | "CMP bot, mov, cur, bot;"
|
---|
1950 | "CMP top, field, top, cur;"
|
---|
1951 | "CMP bot, field, cur, bot;"
|
---|
1952 | "CMP result.color, off.y, top, bot;";
|
---|
1953 | break;
|
---|
1954 | case kBOBDEINT:
|
---|
1955 | case kONEFIELD:
|
---|
1956 | ret +=
|
---|
1957 | "ATTRIB tex = fragment.texcoord[0];"
|
---|
1958 | "PARAM off = program.env[0];"
|
---|
1959 | "TEMP field, top, bottom, current, other;"
|
---|
1960 | "TEX current, tex, texture[0], %1;"
|
---|
1961 | "RCP field, off.x;"
|
---|
1962 | "MUL field, tex.yyyy, field;"
|
---|
1963 | "FRC field, field;"
|
---|
1964 | "SUB field, field, 0.5;"
|
---|
1965 | "ADD top, tex, off.wyww;"
|
---|
1966 | "TEX other, top, texture[0], %1;"
|
---|
1967 | "CMP top, field, other, current;"
|
---|
1968 | "CMP bottom, field, current, other;"
|
---|
1969 | "CMP result.color, off.y, top, bottom;";
|
---|
1970 | break;
|
---|
1971 | case kLINBLEND:
|
---|
1972 | ret +=
|
---|
1973 | "ATTRIB tex = fragment.texcoord[0];"
|
---|
1974 | "PARAM off = program.env[0];"
|
---|
1975 | "TEMP mov, field, cur, pre, pos;"
|
---|
1976 | "RCP field, off.x;"
|
---|
1977 | "MUL field, tex.yyyy, field;"
|
---|
1978 | "FRC field, field;"
|
---|
1979 | "SUB field, field, 0.5;"
|
---|
1980 | "TEX cur, tex, texture[0], %1;"
|
---|
1981 | "TEX pre, tex, texture[1], %1;"
|
---|
1982 | "SUB mov, cur, pre;"
|
---|
1983 | "ABS mov, mov;"
|
---|
1984 | "SUB mov, mov, 0.12;"
|
---|
1985 | "ADD pos, tex, off.wyww;"
|
---|
1986 | "TEX pre, pos, texture[0], %1;"
|
---|
1987 | "SUB pos, tex, off.wyww;"
|
---|
1988 | "TEX pos, pos, texture[0], %1;"
|
---|
1989 | "LRP pre, 0.5, pos, pre;"
|
---|
1990 | "CMP pre, field, pre, cur;"
|
---|
1991 | "CMP result.color, mov, cur, pre;";
|
---|
1992 | break;
|
---|
1993 | case kNOFILT:
|
---|
1994 | case kRESIZE:
|
---|
1995 | break;
|
---|
1996 | default:
|
---|
1997 | VERBOSE(VB_PLAYBACK, LOC_ERR + "Unknown fragment program.");
|
---|
1998 | }
|
---|
1999 | return ret + "END";
|
---|
2000 | }
|
---|
2001 |
|
---|