00001 #include "NuppelVideoPlayer.h"
00002
00003
00004
00005
00006 #include <cstdlib>
00007 #include <cstring>
00008 #include <cmath>
00009 #include <ctime>
00010 #include <cerrno>
00011
00012 #ifdef HAVE_MALLOC_H
00013 #include <malloc.h>
00014 #endif
00015 #include <fcntl.h>
00016 #include <unistd.h>
00017 #include <sys/time.h>
00018 #include <sys/ipc.h>
00019 #include <sys/shm.h>
00020 #include <X11/keysym.h>
00021
00022 #include <algorithm>
00023 #include <iostream>
00024 using namespace std;
00025
00026
00027 #include "yuv2rgb.h"
00028 #include "osd.h"
00029 #include "osdsurface.h"
00030 #include "osdxvmc.h"
00031 #include "osdchromakey.h"
00032
00033
00034 #include "videoout_xv.h"
00035 #include "util-x11.h"
00036 #include "util-xv.h"
00037 #include "util-xvmc.h"
00038 #include "xvmctextures.h"
00039
00040
00041 #include "mythconfig.h"
00042 #include "mythcontext.h"
00043 #include "filtermanager.h"
00044 #include "videodisplayprofile.h"
00045 #define IGNORE_TV_PLAY_REC
00046 #include "tv.h"
00047 #include "fourcc.h"
00048
00049
00050 #include "openglcontext.h"
00051 #include "openglvideo.h"
00052
00053 #define LOC QString("VideoOutputXv: ")
00054 #define LOC_ERR QString("VideoOutputXv Error: ")
00055
00056 extern "C" {
00057 #define XMD_H 1
00058 #include <X11/extensions/xf86vmode.h>
00059 #include <X11/extensions/Xinerama.h>
00060 extern int XShmQueryExtension(Display*);
00061 extern int XShmGetEventBase(Display*);
00062 extern XvImage *XvShmCreateImage(Display*, XvPortID, int, char*,
00063 int, int, XShmSegmentInfo*);
00064 }
00065
00066 #ifndef HAVE_ROUND
00067 #define round(x) ((int) ((x) + 0.5))
00068 #endif
00069
00070 #ifndef XVMC_CHROMA_FORMAT_420
00071 #define XVMC_CHROMA_FORMAT_420 0x00000001
00072 #endif
00073
00074 static QStringList allowed_video_renderers(MythCodecID codec_id,
00075 Display *XJ_disp);
00076
00077 static void SetFromEnv(bool &useXvVLD, bool &useXvIDCT, bool &useXvMC,
00078 bool &useXV, bool &useShm, bool &useOpenGL);
00079 static void SetFromHW(Display *d, bool &useXvMC, bool &useXV,
00080 bool &useShm, bool &useXvMCOpenGL, bool &useOpenGL);
00081 static int calc_hue_base(const QString &adaptor_name);
00082
00083 const char *vr_str[] =
00084 {
00085 "unknown", "xlib", "xshm", "opengl", "xv-blit", "xvmc", "xvmc", "xvmc",
00086 };
00087
00100 VideoOutputXv::VideoOutputXv(MythCodecID codec_id)
00101 : VideoOutput(),
00102 myth_codec_id(codec_id), video_output_subtype(XVUnknown),
00103 display_res(NULL), global_lock(true),
00104
00105 XJ_root(0), XJ_win(0), XJ_curwin(0), XJ_gc(0), XJ_screen(NULL),
00106 XJ_disp(NULL), XJ_screen_num(0),
00107 XJ_white(0), XJ_black(0), XJ_letterbox_colour(0), XJ_depth(0),
00108 XJ_screenx(0), XJ_screeny(0), XJ_screenwidth(0), XJ_screenheight(0),
00109 XJ_started(false),
00110
00111 XJ_non_xv_image(0), non_xv_frames_shown(0), non_xv_show_frame(1),
00112 non_xv_fps(0), non_xv_av_format(PIX_FMT_NB), non_xv_stop_time(0),
00113
00114 xvmc_buf_attr(new XvMCBufferSettings()),
00115 xvmc_chroma(XVMC_CHROMA_FORMAT_420), xvmc_ctx(NULL),
00116 xvmc_osd_lock(false),
00117 xvmc_tex(NULL),
00118
00119 xv_port(-1), xv_hue_base(0),
00120 xv_colorkey(0), xv_draw_colorkey(false),
00121 xv_chroma(0),
00122
00123 gl_context_lock(false), gl_context(NULL),
00124 gl_videochain(NULL), gl_pipchain(NULL),
00125 gl_osdchain(NULL),
00126
00127 gl_use_osd_opengl2(false),
00128 gl_pip_ready(false),
00129 gl_osd_ready(false),
00130
00131
00132 chroma_osd(NULL)
00133 {
00134 VERBOSE(VB_PLAYBACK, LOC + "ctor");
00135 bzero(&av_pause_frame, sizeof(av_pause_frame));
00136
00137
00138
00139 if (gContext->GetNumSetting("UseVideoModes", 0))
00140 display_res = DisplayRes::GetDisplayRes();
00141 }
00142
00143 VideoOutputXv::~VideoOutputXv()
00144 {
00145 VERBOSE(VB_PLAYBACK, LOC + "dtor");
00146 if (XJ_started)
00147 {
00148 X11L;
00149 XSetForeground(XJ_disp, XJ_gc, XJ_black);
00150 XFillRectangle(XJ_disp, XJ_curwin, XJ_gc,
00151 display_visible_rect.left(),
00152 display_visible_rect.top(),
00153 display_visible_rect.width(),
00154 display_visible_rect.height());
00155 X11U;
00156
00157 m_deinterlacing = false;
00158 }
00159
00160
00161 DeleteBuffers(VideoOutputSubType(), true);
00162
00163 if (gl_context)
00164 {
00165 QMutexLocker locker(&gl_context_lock);
00166 delete gl_context;
00167 gl_context = NULL;
00168 }
00169
00170
00171 if (xv_port >= 0)
00172 {
00173 VERBOSE(VB_PLAYBACK, LOC + "Closing XVideo port " << xv_port);
00174 X11L;
00175 XvUngrabPort(XJ_disp, xv_port, CurrentTime);
00176 del_open_xv_port(xv_port);
00177 X11U;
00178 xv_port = -1;
00179 }
00180
00181 if (XJ_started)
00182 {
00183 XJ_started = false;
00184
00185 X11L;
00186 XFreeGC(XJ_disp, XJ_gc);
00187 XCloseDisplay(XJ_disp);
00188 X11U;
00189 }
00190
00191 if (xvmc_buf_attr)
00192 delete xvmc_buf_attr;
00193
00194
00195 if (display_res)
00196 display_res->SwitchToGUI();
00197 }
00198
00199
00200 void VideoOutputXv::Zoom(ZoomDirection direction)
00201 {
00202 QMutexLocker locker(&global_lock);
00203 VideoOutput::Zoom(direction);
00204 MoveResize();
00205 }
00206
00207
00208 void VideoOutputXv::MoveResize(void)
00209 {
00210 QMutexLocker locker(&global_lock);
00211 VideoOutput::MoveResize();
00212 if (chroma_osd)
00213 {
00214 chroma_osd->Reset();
00215 needrepaint = true;
00216 }
00217
00218 if (gl_videochain)
00219 {
00220 QMutexLocker locker(&gl_context_lock);
00221 gl_videochain->SetVideoRect(display_video_rect, video_rect);
00222 }
00223 }
00224
00225
00226 bool VideoOutputXv::InputChanged(const QSize &input_size,
00227 float aspect,
00228 MythCodecID av_codec_id,
00229 void *codec_private)
00230 {
00231 VERBOSE(VB_PLAYBACK, LOC + QString("InputChanged(%1,%2,%3) '%4'->'%5'")
00232 .arg(input_size.width()).arg(input_size.height()).arg(aspect)
00233 .arg(toString(myth_codec_id)).arg(toString(av_codec_id)));
00234
00235 QMutexLocker locker(&global_lock);
00236
00237 bool cid_changed = (myth_codec_id != av_codec_id);
00238 bool res_changed = input_size != video_disp_dim;
00239 bool asp_changed = aspect != video_aspect;
00240
00241 VideoOutput::InputChanged(input_size, aspect, av_codec_id, codec_private);
00242
00243 if (!res_changed && !cid_changed)
00244 {
00245 if (VideoOutputSubType() == XVideo)
00246 vbuffers.Clear(xv_chroma);
00247 if (asp_changed)
00248 MoveResize();
00249 return true;
00250 }
00251
00252 bool ok = true;
00253
00254 DeleteBuffers(VideoOutputSubType(),
00255 cid_changed || (OpenGL == VideoOutputSubType()));
00256 ResizeForVideo((uint) video_disp_dim.width(),
00257 (uint) video_disp_dim.height());
00258
00259 if (cid_changed && (OpenGL != VideoOutputSubType()))
00260 {
00261 myth_codec_id = av_codec_id;
00262
00263
00264 if (xv_port >= 0)
00265 {
00266 VERBOSE(VB_PLAYBACK, LOC + "Closing XVideo port " << xv_port);
00267 X11L;
00268 XvUngrabPort(XJ_disp, xv_port, CurrentTime);
00269 del_open_xv_port(xv_port);
00270 X11U;
00271 xv_port = -1;
00272 }
00273
00274 ok = InitSetupBuffers();
00275 }
00276 else if (OpenGL != VideoOutputSubType())
00277 ok = CreateBuffers(VideoOutputSubType());
00278
00279 if (OpenGL == VideoOutputSubType())
00280 {
00281 myth_codec_id = av_codec_id;
00282 ok = InitSetupBuffers();
00283 }
00284
00285 MoveResize();
00286
00287 if (!ok)
00288 {
00289 VERBOSE(VB_IMPORTANT, LOC_ERR + "InputChanged(): "
00290 "Failed to recreate buffers");
00291 errored = true;
00292 }
00293
00294 return ok;
00295 }
00296
00297
00298 QRect VideoOutputXv::GetVisibleOSDBounds(
00299 float &visible_aspect, float &font_scaling, float themeaspect) const
00300 {
00301
00302 QSize dvr2 = QSize(display_visible_rect.width() & ~0x3,
00303 display_visible_rect.height() & ~0x1);
00304
00305 if (!chroma_osd && !gl_use_osd_opengl2)
00306 return VideoOutput::GetVisibleOSDBounds(visible_aspect, font_scaling, themeaspect);
00307
00308 float dispPixelAdj = 1.0f;
00309 if (dvr2.height() && dvr2.width())
00310 dispPixelAdj = (GetDisplayAspect() * dvr2.height()) / dvr2.width();
00311 visible_aspect = themeaspect / dispPixelAdj;
00312 font_scaling = 1.0f;
00313 return QRect(QPoint(0,0), dvr2);
00314 }
00315
00316
00317 QRect VideoOutputXv::GetTotalOSDBounds(void) const
00318 {
00319 QSize dvr2 = QSize(display_visible_rect.width() & ~0x3,
00320 display_visible_rect.height() & ~0x1);
00321
00322 QSize sz = (chroma_osd || gl_use_osd_opengl2) ? dvr2 : video_disp_dim;
00323 return QRect(QPoint(0,0), sz);
00324 }
00325
00338 int VideoOutputXv::GetRefreshRate(void)
00339 {
00340 if (!XJ_started)
00341 return -1;
00342
00343 XF86VidModeModeLine mode_line;
00344 int dot_clock;
00345
00346 int ret = False;
00347 X11S(ret = XF86VidModeGetModeLine(XJ_disp, XJ_screen_num,
00348 &dot_clock, &mode_line));
00349 if (!ret)
00350 {
00351 VERBOSE(VB_IMPORTANT, LOC_ERR + "GetRefreshRate(): "
00352 "X11 ModeLine query failed");
00353 return -1;
00354 }
00355
00356 double rate = mode_line.htotal * mode_line.vtotal;
00357
00358
00359 if (rate == 0.0 || dot_clock == 0)
00360 {
00361 VERBOSE(VB_IMPORTANT, LOC_ERR + "GetRefreshRate(): "
00362 "X11 ModeLine query returned zeroes");
00363 return -1;
00364 }
00365
00366 rate = (dot_clock * 1000.0) / rate;
00367
00368
00369 if (rate < 20 || rate > 200)
00370 {
00371 VERBOSE(VB_PLAYBACK, LOC + QString("Unreasonable refresh rate %1Hz "
00372 "reported by X").arg(rate));
00373 rate = 60;
00374 }
00375
00376 rate = 1000000.0 / rate;
00377
00378 return (int)rate;
00379 }
00380
00381 void VideoOutputXv::ResizeForVideo(void)
00382 {
00383 ResizeForVideo(video_disp_dim.width(), video_disp_dim.height());
00384 }
00385
00386 void VideoOutputXv::ResizeForGui(void)
00387 {
00388 if (display_res)
00389 display_res->SwitchToGUI();
00390 }
00391
00403 void VideoOutputXv::ResizeForVideo(uint width, uint height)
00404 {
00405 if ((width == 1920 || width == 1440) && height == 1088)
00406 height = 1080;
00407
00408 if (display_res && display_res->SwitchToVideo(width, height))
00409 {
00410
00411
00412 display_dim = QSize(display_res->GetPhysicalWidth(),
00413 display_res->GetPhysicalHeight());
00414 display_aspect = display_res->GetAspectRatio();
00415
00416 bool fullscreen = !gContext->GetNumSetting("GuiSizeForTV", 0);
00417
00418
00419 if (!fullscreen)
00420 {
00421 int gui_width = 0, gui_height = 0;
00422 gContext->GetResolutionSetting("Gui", gui_width, gui_height);
00423 fullscreen |= (0 == gui_width && 0 == gui_height);
00424 }
00425
00426 if (fullscreen)
00427 {
00428 QSize sz(display_res->GetWidth(), display_res->GetHeight());
00429 display_visible_rect = QRect(QPoint(0,0), sz);
00430
00431
00432 X11S(XMoveResizeWindow(XJ_disp, XJ_win,
00433 display_visible_rect.left(),
00434 display_visible_rect.top(),
00435 display_visible_rect.width(),
00436 display_visible_rect.height()));
00437 }
00438 }
00439 }
00440
00446 void VideoOutputXv::InitDisplayMeasurements(uint width, uint height)
00447 {
00448 if (display_res)
00449 {
00450
00451
00452
00453 X11S(XMoveResizeWindow(XJ_disp, XJ_win, 0, 0,
00454 display_res->GetMaxWidth(),
00455 display_res->GetMaxHeight()));
00456 ResizeForVideo(width, height);
00457 }
00458 else
00459 {
00460 display_dim = MythXGetDisplayDimensions(XJ_disp, XJ_screen_num);
00461
00462 if (db_display_dim.width() > 0 && db_display_dim.height() > 0)
00463 display_dim = db_display_dim;
00464
00465
00466 float wmult, hmult;
00467 gContext->GetScreenSettings(XJ_screenx, XJ_screenwidth, wmult,
00468 XJ_screeny, XJ_screenheight, hmult);
00469 }
00470
00471
00472 int xbase, ybase, w, h;
00473 gContext->GetScreenBounds(xbase, ybase, w, h);
00474
00475
00476 int window_w = w, window_h = h;
00477 if (gContext->GetNumSetting("GuiSizeForTV", 0))
00478 gContext->GetResolutionSetting("Gui", window_w, window_h);
00479 else
00480 gContext->GetScreenBounds(xbase, ybase, window_w, window_h);
00481 window_w = (window_w) ? window_w : w;
00482 window_h = (window_h) ? window_h : h;
00483 float pixel_aspect = ((float)w) / ((float)h);
00484
00485 VERBOSE(VB_PLAYBACK, LOC + QString(
00486 "Pixel dimensions: Screen %1x%2, window %3x%4")
00487 .arg(w).arg(h).arg(window_w).arg(window_h));
00488
00489
00490 bool usingXinerama = (GetNumberOfXineramaScreens() > 1);
00491
00492
00493
00494 if (((display_dim.width() <= 0) || (display_dim.height() <= 0)) &&
00495 !usingXinerama)
00496 {
00497 VERBOSE(VB_GENERAL, LOC + "Physical size of display unknown."
00498 "\n\t\t\tAssuming 17\" monitor with square pixels.");
00499 display_dim.setHeight(300);
00500 display_dim.setWidth((int) round(300 * pixel_aspect));
00501 }
00502
00503
00504
00505
00506
00507 if (usingXinerama)
00508 {
00509 float displayAspect = gContext->GetFloatSettingOnHost(
00510 "XineramaMonitorAspectRatio",
00511 gContext->GetHostName(), pixel_aspect);
00512 int height = display_dim.height();
00513 if (height <= 0)
00514 display_dim.setHeight(height = 300);
00515 display_dim.setWidth((int) round(height * displayAspect));
00516 }
00517
00518 VERBOSE(VB_PLAYBACK, LOC +
00519 QString("Estimated display dimensions: %1x%2 mm Aspect: %3")
00520 .arg(display_dim.width()).arg(display_dim.height())
00521 .arg(((float) display_dim.width()) / display_dim.height()));
00522
00523
00524
00525 display_dim = QSize((display_dim.width() * window_w) / w,
00526 (display_dim.height() * window_h) / h);
00527
00528
00529
00530 display_aspect = ((float)display_dim.width()) / display_dim.height();
00531
00532
00533 if (display_res)
00534 display_aspect = display_res->GetAspectRatio();
00535
00536 VERBOSE(VB_PLAYBACK, LOC +
00537 QString("Estimated window dimensions: %1x%2 mm Aspect: %3")
00538 .arg(display_dim.width()).arg(display_dim.height())
00539 .arg(display_aspect));
00540 }
00541
00542 class XvAttributes
00543 {
00544 public:
00545 XvAttributes() :
00546 description(QString::null), xv_flags(0), feature_flags(0) {}
00547 XvAttributes(const QString &a, uint b, uint c) :
00548 description(QDeepCopy<QString>(a)), xv_flags(b), feature_flags(c) {}
00549
00550 public:
00551 QString description;
00552 uint xv_flags;
00553 uint feature_flags;
00554
00555 static const uint kFeatureNone = 0x0000;
00556 static const uint kFeatureXvMC = 0x0001;
00557 static const uint kFeatureVLD = 0x0002;
00558 static const uint kFeatureIDCT = 0x0004;
00559 static const uint kFeatureChromakey = 0x0008;
00560 static const uint kFeaturePicCtrl = 0x0010;
00561 };
00562
00568 int VideoOutputXv::GrabSuitableXvPort(Display* disp, Window root,
00569 MythCodecID mcodecid,
00570 uint width, uint height,
00571 int xvmc_chroma,
00572 XvMCSurfaceInfo* xvmc_surf_info,
00573 QString *adaptor_name)
00574 {
00575
00576 (void)xvmc_chroma; (void)xvmc_surf_info;
00577
00578 if (adaptor_name)
00579 *adaptor_name = QString::null;
00580
00581
00582 int stream_type = 0;
00583 bool need_mc = false, need_idct = false;
00584 bool need_vld = false, need_xv = false;
00585 switch (mcodecid)
00586 {
00587 case kCodec_MPEG1_XVMC: stream_type = 1; need_mc = true; break;
00588 case kCodec_MPEG2_XVMC: stream_type = 2; need_mc = true; break;
00589 case kCodec_H263_XVMC: stream_type = 3; need_mc = true; break;
00590 case kCodec_MPEG4_XVMC: stream_type = 4; need_mc = true; break;
00591
00592 case kCodec_MPEG1_IDCT: stream_type = 1; need_idct = true; break;
00593 case kCodec_MPEG2_IDCT: stream_type = 2; need_idct = true; break;
00594 case kCodec_H263_IDCT: stream_type = 3; need_idct = true; break;
00595 case kCodec_MPEG4_IDCT: stream_type = 4; need_idct = true; break;
00596
00597 case kCodec_MPEG1_VLD: stream_type = 1; need_vld = true; break;
00598 case kCodec_MPEG2_VLD: stream_type = 2; need_vld = true; break;
00599 case kCodec_H263_VLD: stream_type = 3; need_vld = true; break;
00600 case kCodec_MPEG4_VLD: stream_type = 4; need_vld = true; break;
00601
00602 default:
00603 need_xv = true;
00604 break;
00605 }
00606
00607
00608 vector<XvAttributes> req;
00609 if (need_vld)
00610 {
00611 req.push_back(XvAttributes(
00612 "XvMC surface found with VLD support on port %1",
00613 XvInputMask, XvAttributes::kFeatureXvMC |
00614 XvAttributes::kFeatureVLD));
00615 }
00616
00617 if (need_idct)
00618 {
00619 req.push_back(XvAttributes(
00620 "XvMC surface found with IDCT support on port %1",
00621 XvInputMask, XvAttributes::kFeatureXvMC |
00622 XvAttributes::kFeatureIDCT));
00623 }
00624
00625 if (need_mc)
00626 {
00627 req.push_back(XvAttributes(
00628 "XvMC surface found with MC support on port %1",
00629 XvInputMask, XvAttributes::kFeatureXvMC));
00630 }
00631
00632 if (need_xv)
00633 {
00634 req.push_back(XvAttributes(
00635 "XVideo surface found on port %1",
00636 XvInputMask | XvImageMask,
00637 XvAttributes::kFeatureNone));
00638 }
00639
00640
00641 if (true)
00642 {
00643 uint end = req.size();
00644 for (uint i = 0; i < end; i++)
00645 {
00646 req.push_back(req[i]);
00647 req[i].feature_flags |= XvAttributes::kFeaturePicCtrl;
00648 }
00649 }
00650
00651
00652 VideoDisplayProfile vdp;
00653 vdp.SetInput(QSize(width, height));
00654 bool check_for_colorkey = (vdp.GetOSDRenderer() == "chromakey");
00655
00656
00657 if (check_for_colorkey)
00658 {
00659 uint end = req.size();
00660 for (uint i = 0; i < end; i++)
00661 {
00662 req.push_back(req[i]);
00663 req[i].feature_flags |= XvAttributes::kFeatureChromakey;
00664 }
00665 }
00666
00667
00668 XvAdaptorInfo *ai = NULL;
00669 uint p_num_adaptors = 0;
00670 int ret = Success;
00671 X11S(ret = XvQueryAdaptors(disp, root, &p_num_adaptors, &ai));
00672 if (Success != ret)
00673 {
00674 VERBOSE(VB_IMPORTANT, LOC +
00675 "XVideo supported, but no free Xv ports found."
00676 "\n\t\t\tYou may need to reload video driver.");
00677 return -1;
00678 }
00679
00680 QString lastAdaptorName = QString::null;
00681 int port = -1;
00682
00683
00684 for (uint j = 0; j < req.size(); ++j)
00685 {
00686 VERBOSE(VB_PLAYBACK, LOC + QString("@ j=%1 Looking for flag[s]: %2 %3")
00687 .arg(j).arg(xvflags2str(req[j].xv_flags))
00688 .arg(req[j].feature_flags,0,16));
00689
00690 for (int i = 0; i < (int)p_num_adaptors && (port == -1); ++i)
00691 {
00692 lastAdaptorName = ai[i].name;
00693 VERBOSE(VB_PLAYBACK, LOC +
00694 QString("Adaptor#%1: %2 has flag[s]: %3")
00695 .arg(i).arg(lastAdaptorName).arg(xvflags2str(ai[i].type)));
00696
00697 if ((ai[i].type & req[j].xv_flags) != req[j].xv_flags)
00698 {
00699 VERBOSE(VB_PLAYBACK, LOC + "Missing XVideo flags, rejecting.");
00700 continue;
00701 }
00702 else
00703 VERBOSE(VB_PLAYBACK, LOC + "Has XVideo flags...");
00704
00705 const XvPortID firstPort = ai[i].base_id;
00706 const XvPortID lastPort = ai[i].base_id + ai[i].num_ports - 1;
00707 XvPortID p = 0;
00708
00709 if ((req[j].feature_flags & XvAttributes::kFeaturePicCtrl) &&
00710 (!xv_is_attrib_supported(disp, firstPort, "XV_BRIGHTNESS")))
00711 {
00712 VERBOSE(VB_PLAYBACK, LOC +
00713 "Missing XV_BRIGHTNESS, rejecting.");
00714 continue;
00715 }
00716 else if (req[j].feature_flags & XvAttributes::kFeaturePicCtrl)
00717 VERBOSE(VB_PLAYBACK, LOC + "Has XV_BRIGHTNESS...");
00718
00719 if ((req[j].feature_flags & XvAttributes::kFeatureChromakey) &&
00720 (!xv_is_attrib_supported(disp, firstPort, "XV_COLORKEY")))
00721 {
00722 VERBOSE(VB_PLAYBACK, LOC +
00723 "Missing XV_COLORKEY, rejecting.");
00724 continue;
00725 }
00726 else if (req[j].feature_flags & XvAttributes::kFeatureChromakey)
00727 VERBOSE(VB_PLAYBACK, LOC + "Has XV_COLORKEY...");
00728
00729 VERBOSE(VB_PLAYBACK, LOC + "Here...");
00730
00731 if (req[j].feature_flags & XvAttributes::kFeatureXvMC)
00732 {
00733 #ifdef USING_XVMC
00734 int surfNum;
00735 XvMCSurfaceTypes::find(
00736 width, height, xvmc_chroma,
00737 req[j].feature_flags & XvAttributes::kFeatureVLD,
00738 req[j].feature_flags & XvAttributes::kFeatureIDCT,
00739 stream_type,
00740 0, 0,
00741 disp, firstPort, lastPort,
00742 p, surfNum);
00743
00744 if (surfNum<0)
00745 continue;
00746
00747 XvMCSurfaceTypes surf(disp, p);
00748
00749 if (!surf.size())
00750 continue;
00751
00752 X11L;
00753 ret = XvGrabPort(disp, p, CurrentTime);
00754 if (Success == ret)
00755 {
00756 VERBOSE(VB_PLAYBACK, LOC + "Grabbed xv port "<<p);
00757 port = p;
00758 add_open_xv_port(disp, p);
00759 }
00760 X11U;
00761 if (Success != ret)
00762 {
00763 VERBOSE(VB_PLAYBACK, LOC + "Failed to grab xv port "<<p);
00764 continue;
00765 }
00766
00767 if (xvmc_surf_info)
00768 surf.set(surfNum, xvmc_surf_info);
00769 #endif // USING_XVMC
00770 }
00771 else
00772 {
00773 for (p = firstPort; (p <= lastPort) && (port == -1); ++p)
00774 {
00775 X11L;
00776 ret = XvGrabPort(disp, p, CurrentTime);
00777 if (Success == ret)
00778 {
00779 VERBOSE(VB_PLAYBACK, LOC + "Grabbed xv port "<<p);
00780 port = p;
00781 add_open_xv_port(disp, p);
00782 }
00783 X11U;
00784 }
00785 }
00786 }
00787 if (port != -1)
00788 {
00789 VERBOSE(VB_PLAYBACK, LOC + req[j].description.arg(port));
00790 break;
00791 }
00792 }
00793 if (port == -1)
00794 VERBOSE(VB_PLAYBACK, LOC + "No suitable XVideo port found");
00795
00796
00797 if (ai)
00798 X11S(XvFreeAdaptorInfo(ai));
00799
00800 if ((port != -1) && adaptor_name)
00801 *adaptor_name = lastAdaptorName;
00802
00803 return port;
00804 }
00805
00816 void VideoOutputXv::CreatePauseFrame(VOSType subtype)
00817 {
00818
00819 if ((subtype <= XVideo) || (subtype == OpenGL))
00820 {
00821 vbuffers.LockFrame(&av_pause_frame, "CreatePauseFrame");
00822
00823 if (av_pause_frame.buf)
00824 {
00825 delete [] av_pause_frame.buf;
00826 av_pause_frame.buf = NULL;
00827 }
00828
00829 init(&av_pause_frame, FMT_YV12,
00830 new unsigned char[vbuffers.GetScratchFrame()->size + 128],
00831 vbuffers.GetScratchFrame()->width,
00832 vbuffers.GetScratchFrame()->height,
00833 vbuffers.GetScratchFrame()->bpp,
00834 vbuffers.GetScratchFrame()->size);
00835
00836 av_pause_frame.frameNumber = vbuffers.GetScratchFrame()->frameNumber;
00837
00838 clear(&av_pause_frame, xv_chroma);
00839
00840 vbuffers.UnlockFrame(&av_pause_frame, "CreatePauseFrame");
00841 }
00842 }
00843
00855 bool VideoOutputXv::InitVideoBuffers(MythCodecID mcodecid,
00856 bool use_xv, bool use_shm,
00857 bool use_opengl)
00858 {
00859 (void)mcodecid;
00860
00861 bool done = false;
00862
00863 #ifdef USING_XVMC
00864 if (mcodecid > kCodec_NORMAL_END)
00865 {
00866
00867 bool vld, idct, mc;
00868 myth2av_codecid(myth_codec_id, vld, idct, mc);
00869
00870 vbuffers.Init(xvmc_buf_attr->GetNumSurf(),
00871 false ,
00872 xvmc_buf_attr->GetFrameReserve(),
00873 xvmc_buf_attr->GetPreBufferGoal(),
00874 xvmc_buf_attr->GetPreBufferGoal(),
00875 xvmc_buf_attr->GetNeededBeforeDisplay(),
00876 true );
00877
00878
00879 done = InitXvMC(mcodecid);
00880
00881 if (!done)
00882 vbuffers.Reset();
00883 }
00884 #endif // USING_XVMC
00885
00886
00887 if (!done)
00888 vbuffers.Init(31, true, 1, 12, 4, 2, false);
00889
00890 if (!done && use_opengl)
00891 done = InitOpenGL();
00892
00893
00894 if (!done && use_xv)
00895 done = InitXVideo();
00896
00897
00898 if (!done && use_shm)
00899 done = InitXShm();
00900
00901
00902 if (!done)
00903 done = InitXlib();
00904
00905 QString tmp = vr_str[VideoOutputSubType()];
00906 QString rend = db_vdisp_profile->GetVideoRenderer();
00907 if ((tmp == "xvmc") && (rend.left(4) == "xvmc"))
00908 tmp = rend;
00909 db_vdisp_profile->SetVideoRenderer(tmp);
00910
00911 return done;
00912 }
00913
00914 bool VideoOutputXv::InitOpenGL(void)
00915 {
00916 bool ok = false;
00917
00918 #ifdef USING_OPENGL_VIDEO
00919 ok = gl_context;
00920
00921 gl_context_lock.lock();
00922
00923 if (!ok)
00924 {
00925 gl_context = new OpenGLContext();
00926
00927 ok = gl_context->Create(
00928 XJ_disp, XJ_win, XJ_screen_num,
00929 display_visible_rect.size(), true);
00930 }
00931
00932 if (ok)
00933 {
00934 gl_context->Show();
00935 gl_context->MakeCurrent(true);
00936 gl_videochain = new OpenGLVideo();
00937 ok = gl_videochain->Init(gl_context, db_use_picture_controls,
00938 true, video_dim,
00939 display_visible_rect,
00940 display_video_rect, video_rect, true);
00941 gl_context->MakeCurrent(false);
00942 }
00943
00944 gl_context_lock.unlock();
00945
00946 if (ok)
00947 {
00948 InstallXErrorHandler(XJ_disp);
00949
00950 ok = CreateBuffers(OpenGL);
00951
00952 vector<XErrorEvent> errs = UninstallXErrorHandler(XJ_disp);
00953 if (!ok || errs.size())
00954 {
00955 VERBOSE(VB_IMPORTANT, LOC_ERR +
00956 "Failed to allocate video buffers.");
00957
00958 PrintXErrors(XJ_disp, errs);
00959 DeleteBuffers(OpenGL, false);
00960 ok = false;
00961 }
00962 else
00963 {
00964 video_output_subtype = OpenGL;
00965 allowpreviewepg = false;
00966
00967
00968 bool temp_deinterlacing = m_deinterlacing;
00969
00970 if (!m_deintfiltername.isEmpty() &&
00971 !m_deintfiltername.contains("opengl"))
00972 {
00973 QMutexLocker locker(&gl_context_lock);
00974 gl_videochain->SetSoftwareDeinterlacer(m_deintfiltername);
00975 }
00976
00977 SetDeinterlacingEnabled(true);
00978
00979 if (!temp_deinterlacing)
00980 {
00981 SetDeinterlacingEnabled(false);
00982 }
00983 }
00984 }
00985
00986 if (!ok)
00987 {
00988 QMutexLocker locker(&gl_context_lock);
00989 if (gl_videochain)
00990 {
00991 delete gl_videochain;
00992 gl_videochain = NULL;
00993 }
00994
00995 if (gl_context)
00996 {
00997 delete gl_context;
00998 gl_context = NULL;
00999 }
01000 }
01001 #endif // USING_OPENGL_VIDEO
01002
01003 return ok;
01004 }
01005
01014 bool VideoOutputXv::InitXvMC(MythCodecID mcodecid)
01015 {
01016 (void)mcodecid;
01017 #ifdef USING_XVMC
01018 QString adaptor_name = QString::null;
01019 xv_port = GrabSuitableXvPort(XJ_disp, XJ_root, mcodecid,
01020 video_dim.width(), video_dim.height(),
01021 xvmc_chroma, &xvmc_surf_info, &adaptor_name);
01022 if (xv_port == -1)
01023 {
01024 VERBOSE(VB_IMPORTANT, LOC_ERR +
01025 "Could not find suitable XvMC surface.");
01026 return false;
01027 }
01028
01029 VERBOSE(VB_IMPORTANT, LOC + QString("XvMC Adaptor Name: '%1'")
01030 .arg(adaptor_name));
01031
01032 xv_hue_base = calc_hue_base(adaptor_name);
01033
01034 InstallXErrorHandler(XJ_disp);
01035
01036
01037 bool ok = CreateXvMCBuffers();
01038 vector<XErrorEvent> errs = UninstallXErrorHandler(XJ_disp);
01039 if (!ok || errs.size())
01040 {
01041 PrintXErrors(XJ_disp, errs);
01042 DeleteBuffers(XVideoMC, false);
01043 ok = false;
01044 }
01045
01046 if (ok)
01047 {
01048 video_output_subtype = XVideoMC;
01049 if (XVMC_IDCT == (xvmc_surf_info.mc_type & XVMC_IDCT))
01050 video_output_subtype = XVideoIDCT;
01051 if (XVMC_VLD == (xvmc_surf_info.mc_type & XVMC_VLD))
01052 video_output_subtype = XVideoVLD;
01053 allowpreviewepg = true;
01054 }
01055 else
01056 {
01057 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create XvMC Buffers.");
01058
01059 xvmc_osd_lock.lock();
01060 for (uint i=0; i<xvmc_osd_available.size(); i++)
01061 delete xvmc_osd_available[i];
01062 xvmc_osd_available.clear();
01063 xvmc_osd_lock.unlock();
01064 VERBOSE(VB_PLAYBACK, LOC + "Closing XVideo port " << xv_port);
01065 X11L;
01066 XvUngrabPort(XJ_disp, xv_port, CurrentTime);
01067 del_open_xv_port(xv_port);
01068 X11U;
01069 xv_port = -1;
01070 }
01071
01072 return ok;
01073 #else // USING_XVMC
01074 return false;
01075 #endif // USING_XVMC
01076 }
01077
01078 static bool has_format(XvImageFormatValues *formats, int format_cnt, int id)
01079 {
01080 for (int i = 0; i < format_cnt; i++)
01081 {
01082 if ((formats[i].id == id))
01083 return true;
01084 }
01085
01086 return false;
01087 }
01088
01097 bool VideoOutputXv::InitXVideo()
01098 {
01099 QString adaptor_name = QString::null;
01100 xv_port = GrabSuitableXvPort(XJ_disp, XJ_root, kCodec_MPEG2,
01101 video_dim.width(), video_dim.height(),
01102 0, NULL, &adaptor_name);
01103 if (xv_port == -1)
01104 {
01105 VERBOSE(VB_IMPORTANT, LOC_ERR +
01106 "Could not find suitable XVideo surface.");
01107 return false;
01108 }
01109
01110 VERBOSE(VB_IMPORTANT, LOC + QString("XVideo Adaptor Name: '%1'")
01111 .arg(adaptor_name));
01112
01113 xv_hue_base = calc_hue_base(adaptor_name);
01114
01115 InstallXErrorHandler(XJ_disp);
01116
01117 bool foundimageformat = false;
01118 int ids[] = { GUID_YV12_PLANAR, GUID_I420_PLANAR, GUID_IYUV_PLANAR, };
01119 int format_cnt = 0;
01120 XvImageFormatValues *formats;
01121 X11S(formats = XvListImageFormats(XJ_disp, xv_port, &format_cnt));
01122
01123 for (int i = 0; i < format_cnt; i++)
01124 {
01125 char *chr = (char*) &(formats[i].id);
01126 VERBOSE(VB_PLAYBACK, LOC + QString("XVideo Format #%1 is '%2%3%4%5'")
01127 .arg(i).arg(chr[0]).arg(chr[1]).arg(chr[2]).arg(chr[3]));
01128 }
01129
01130 for (uint i = 0; i < sizeof(ids)/sizeof(int); i++)
01131 {
01132 if (has_format(formats, format_cnt, ids[i]))
01133 {
01134 xv_chroma = ids[i];
01135 foundimageformat = true;
01136 break;
01137 }
01138 }
01139
01140
01141 xv_chroma = (GUID_IYUV_PLANAR == xv_chroma) ? GUID_I420_PLANAR : xv_chroma;
01142
01143 if (formats)
01144 X11S(XFree(formats));
01145
01146 if (foundimageformat)
01147 {
01148 char *chr = (char*) &xv_chroma;
01149 VERBOSE(VB_PLAYBACK, LOC + QString("Using XVideo Format '%1%2%3%4'")
01150 .arg(chr[0]).arg(chr[1]).arg(chr[2]).arg(chr[3]));
01151 }
01152 else
01153 {
01154 VERBOSE(VB_IMPORTANT, LOC_ERR +
01155 "Couldn't find the proper XVideo image format.");
01156 VERBOSE(VB_PLAYBACK, LOC + "Closing XVideo port " << xv_port);
01157 X11L;
01158 XvUngrabPort(XJ_disp, xv_port, CurrentTime);
01159 del_open_xv_port(xv_port);
01160 X11U;
01161 xv_port = -1;
01162 }
01163
01164 bool ok = xv_port >= 0;
01165 if (ok)
01166 ok = CreateBuffers(XVideo);
01167
01168 vector<XErrorEvent> errs = UninstallXErrorHandler(XJ_disp);
01169 if (!ok || errs.size())
01170 {
01171 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create XVideo Buffers.");
01172 DeleteBuffers(XVideo, false);
01173 VERBOSE(VB_PLAYBACK, LOC + "Closing XVideo port " << xv_port);
01174 X11L;
01175 XvUngrabPort(XJ_disp, xv_port, CurrentTime);
01176 del_open_xv_port(xv_port);
01177 X11U;
01178 xv_port = -1;
01179 ok = false;
01180 }
01181 else
01182 {
01183 video_output_subtype = XVideo;
01184 allowpreviewepg = true;
01185 }
01186
01187 return ok;
01188 }
01189
01198 bool VideoOutputXv::InitXShm()
01199 {
01200 InstallXErrorHandler(XJ_disp);
01201
01202 VERBOSE(VB_IMPORTANT, LOC +
01203 "Falling back to X shared memory video output."
01204 "\n\t\t\t *** May be slow ***");
01205
01206 bool ok = CreateBuffers(XShm);
01207
01208 vector<XErrorEvent> errs = UninstallXErrorHandler(XJ_disp);
01209 if (!ok || errs.size())
01210 {
01211 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to allocate X shared memory.");
01212 PrintXErrors(XJ_disp, errs);
01213 DeleteBuffers(XShm, false);
01214 ok = false;
01215 }
01216 else
01217 {
01218 video_output_subtype = XShm;
01219 allowpreviewepg = false;
01220 }
01221
01222 return ok;
01223 }
01224
01233 bool VideoOutputXv::InitXlib()
01234 {
01235 InstallXErrorHandler(XJ_disp);
01236
01237 VERBOSE(VB_IMPORTANT, LOC +
01238 "Falling back to X11 video output over a network socket."
01239 "\n\t\t\t *** May be very slow ***");
01240
01241 bool ok = CreateBuffers(Xlib);
01242
01243 vector<XErrorEvent> errs = UninstallXErrorHandler(XJ_disp);
01244 if (!ok || errs.size())
01245 {
01246 VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create X buffers.");
01247 PrintXErrors(XJ_disp, errs);
01248 DeleteBuffers(Xlib, false);
01249 ok = false;
01250 }
01251 else
01252 {
01253 video_output_subtype = Xlib;
01254 allowpreviewepg = false;
01255 }
01256
01257 return ok;
01258 }
01259
01263 MythCodecID VideoOutputXv::GetBestSupportedCodec(
01264 uint width, uint height,
01265 uint osd_width, uint osd_height,
01266 uint stream_type, int xvmc_chroma,
01267 bool test_surface, bool force_xv)
01268 {
01269 (void)width, (void)height, (void)osd_width, (void)osd_height;
01270 (void)stream_type, (void)xvmc_chroma, (void)test_surface;
01271
01272 if (force_xv)
01273 return (MythCodecID)(kCodec_MPEG1 + (stream_type-1));
01274 #ifdef USING_XVMC
01275 VideoDisplayProfile vdp;
01276 vdp.SetInput(QSize(width, height));
01277 QString dec = vdp.GetDecoder();
01278 if ((dec == "libmpeg2") || (dec == "ffmpeg"))
01279 return (MythCodecID)(kCodec_MPEG1 + (stream_type-1));
01280
01281 Display *disp = MythXOpenDisplay();
01282
01283
01284 bool use_xvmc_vld = false, use_xvmc_idct = false, use_xvmc = false;
01285 bool use_xv = true, use_shm = true, use_opengl = true;
01286
01287 if (dec == "xvmc")
01288 use_xvmc_idct = use_xvmc = true;
01289 else if (dec == "xvmc-vld")
01290 use_xvmc_vld = use_xvmc = true;
01291
01292 SetFromEnv(use_xvmc_vld, use_xvmc_idct, use_xvmc, use_xv,
01293 use_shm, use_opengl);
01294
01295
01296 bool use_xvmc_opengl = use_xvmc;
01297 SetFromHW(disp, use_xvmc, use_xv, use_shm, use_xvmc_opengl, use_opengl);
01298
01299 MythCodecID ret = (MythCodecID)(kCodec_MPEG1 + (stream_type-1));
01300 if (use_xvmc_vld &&
01301 XvMCSurfaceTypes::has(disp, XvVLD, stream_type, xvmc_chroma,
01302 width, height, osd_width, osd_height))
01303 {
01304 ret = (MythCodecID)(kCodec_MPEG1_VLD + (stream_type-1));
01305 }
01306 else if (use_xvmc_idct &&
01307 XvMCSurfaceTypes::has(disp, XvIDCT, stream_type, xvmc_chroma,
01308 width, height, osd_width, osd_height))
01309 {
01310 ret = (MythCodecID)(kCodec_MPEG1_IDCT + (stream_type-1));
01311 }
01312 else if (use_xvmc &&
01313 XvMCSurfaceTypes::has(disp, XvMC, stream_type, xvmc_chroma,
01314 width, height, osd_width, osd_height))
01315 {
01316 ret = (MythCodecID)(kCodec_MPEG1_XVMC + (stream_type-1));
01317 }
01318
01319 bool ok = true;
01320 if (test_surface && ret > kCodec_NORMAL_END)
01321 {
01322 Window root;
01323 XvMCSurfaceInfo info;
01324
01325 ok = false;
01326 X11S(root = DefaultRootWindow(disp));
01327 int port = GrabSuitableXvPort(disp, root, ret, width, height,
01328 xvmc_chroma, &info);
01329 if (port >= 0)
01330 {
01331 XvMCContext *ctx =
01332 CreateXvMCContext(disp, port, info.surface_type_id,
01333 width, height);
01334 ok = NULL != ctx;
01335 DeleteXvMCContext(disp, ctx);
01336 VERBOSE(VB_PLAYBACK, LOC + "Closing XVideo port " << port);
01337 X11L;
01338 XvUngrabPort(disp, port, CurrentTime);
01339 del_open_xv_port(port);
01340 X11U;
01341 }
01342 }
01343 X11S(XCloseDisplay(disp));
01344 X11S(ok |= cnt_open_xv_port() > 0);
01345
01346 if (!ok)
01347 {
01348 QString msg = LOC_ERR + "Could not open XvMC port...\n"
01349 "\n"
01350 "\t\t\tYou may wish to verify that your DISPLAY\n"
01351 "\t\t\tenvironment variable does not use an external\n"
01352 "\t\t\tnetwork connection.\n";
01353 #ifdef USING_XVMCW
01354 msg += "\n"
01355 "\t\t\tYou may also wish to verify that\n"
01356 "\t\t\t/etc/X11/XvMCConfig contains the correct\n"
01357 "\t\t\tvendor's XvMC library.\n";
01358 #endif // USING_XVMCW
01359 VERBOSE(VB_IMPORTANT, msg);
01360 ret = (MythCodecID)(kCodec_MPEG1 + (stream_type-1));
01361 }
01362
01363 return ret;
01364 #else // if !USING_XVMC
01365 return (MythCodecID)(kCodec_MPEG1 + (stream_type-1));
01366 #endif // !USING_XVMC
01367 }
01368
01369 bool VideoOutputXv::InitOSD(const QString &osd_renderer)
01370 {
01371 if (osd_renderer == "opengl")
01372 {
01373 xvmc_tex = XvMCTextures::Create(
01374 XJ_disp, XJ_curwin, XJ_screen_num,
01375 video_dim, GetTotalOSDBounds().size());
01376
01377 if (xvmc_tex)
01378 {
01379 VERBOSE(VB_IMPORTANT, LOC + "XvMCTex: Init succeeded");
01380 xvmc_buf_attr->SetOSDNum(0);
01381 }
01382 else
01383 {
01384 VERBOSE(VB_IMPORTANT, LOC + "XvMCTex: Init failed");
01385 }
01386
01387 return xvmc_tex;
01388 }
01389
01390 if (osd_renderer == "opengl2")
01391 {
01392 QMutexLocker locker(&gl_context_lock);
01393 gl_use_osd_opengl2 = true;
01394
01395 gl_context->MakeCurrent(true);
01396
01397 gl_osdchain = new OpenGLVideo();
01398 if (!gl_osdchain->Init(
01399 gl_context, false, true,
01400 GetTotalOSDBounds().size(),
01401 GetTotalOSDBounds(), display_visible_rect,
01402 QRect(QPoint(0, 0), GetTotalOSDBounds().size()), false, true))
01403 {
01404 VERBOSE(VB_PLAYBACK, LOC_ERR +
01405 "InitOSD(): Failed to create OpenGL2 OSD");
01406 delete gl_osdchain;
01407 gl_osdchain = NULL;
01408 gl_use_osd_opengl2 = false;
01409 }
01410 else if (gl_videochain)
01411 {
01412 gl_osdchain->SetMasterViewport(gl_videochain->GetViewPort());
01413 }
01414
01415 gl_context->MakeCurrent(false);
01416 }
01417
01418 if (osd_renderer == "chromakey")
01419 {
01420
01421
01422
01423
01424 if ((32 == XJ_depth) || (24 == XJ_depth))
01425 {
01426 chroma_osd = new ChromaKeyOSD(this);
01427 xvmc_buf_attr->SetOSDNum(0);
01428 }
01429 else
01430 {
01431 VERBOSE(VB_IMPORTANT, LOC + QString(
01432 "Number of bits per pixel is %1, \n\t\t\t"
01433 "but we only support ARGB 32 bbp for ChromaKeyOSD.")
01434 .arg(XJ_depth));
01435 }
01436 return chroma_osd;
01437 }
01438
01439
01440 return true;
01441 }
01442
01443 bool VideoOutputXv::CheckOSDInit(void)
01444 {
01445
01446
01447 if (xv_colorkey || !chroma_osd)
01448 return true;
01449
01450 VERBOSE(VB_IMPORTANT, LOC + "Ack! Disabling ChromaKey OSD"
01451 "\n\t\t\tWe can't use ChromaKey OSD "
01452 "if chromakeying is not supported!");
01453
01454
01455 delete chroma_osd;
01456 chroma_osd = NULL;
01457
01458 if (VideoOutputSubType() >= XVideoMC)
01459 {
01460
01461 DeleteBuffers(VideoOutputSubType(), true);
01462 if (xv_port >= 0)
01463 {
01464 VERBOSE(VB_PLAYBACK, LOC + "Closing XVideo port " << xv_port);
01465 X11L;
01466 XvUngrabPort(XJ_disp, xv_port, CurrentTime);
01467 del_open_xv_port(xv_port);
01468 X11U;
01469 xv_port = -1;
01470 }
01471
01472 xvmc_buf_attr->SetOSDNum(1);
01473 return false;
01474 }
01475
01476 return true;
01477 }
01478
01479 #define XV_INIT_FATAL_ERROR_TEST(test,msg) \
01480 do { \
01481 if (test) \
01482 { \
01483 VERBOSE(VB_IMPORTANT, LOC_ERR + msg << " Exiting playback."); \
01484 errored = true; \
01485 return false; \
01486 } \
01487 } while (false)
01488
01489 static QString toCommaList(const QStringList &list)
01490 {
01491 QString ret = "";
01492 for (QStringList::const_iterator it = list.begin(); it != list.end(); ++it)
01493 ret += *it + ",";
01494
01495 if (ret.length())
01496 return ret.left(ret.length()-1);
01497
01498 return "";
01499 }
01500
01501 bool VideoOutputXv::InitSetupBuffers(void)
01502 {
01503
01504 db_vdisp_profile->SetInput(video_dim);
01505 QStringList renderers = allowed_video_renderers(myth_codec_id, XJ_disp);
01506 QString renderer = QString::null;
01507
01508 QString tmp = db_vdisp_profile->GetVideoRenderer();
01509 VERBOSE(VB_PLAYBACK, LOC + "InitSetupBuffers() "
01510 <<QString("render: %1, allowed: %2")
01511 .arg(tmp).arg(toCommaList(renderers)));
01512
01513 if (renderers.contains(tmp))
01514 renderer = tmp;
01515 else if (renderers.empty())
01516 XV_INIT_FATAL_ERROR_TEST(false, "Failed to find a video renderer");
01517 else
01518 {
01519 QString tmp;
01520 QStringList::const_iterator it = renderers.begin();
01521 for (; it != renderers.end(); ++it)
01522 tmp += *it + ",";
01523
01524 renderer = renderers[0];
01525 VERBOSE(VB_IMPORTANT, LOC + QString(
01526 "Desired video renderer '%1' not available.\n\t\t\t"
01527 "codec '%2' makes '%3' available, using '%4' instead.")
01528 .arg(db_vdisp_profile->GetVideoRenderer())
01529 .arg(toString(myth_codec_id)).arg(tmp).arg(renderer));
01530 db_vdisp_profile->SetVideoRenderer(renderer);
01531 }
01532
01533
01534 bool use_xv = (renderer.left(2) == "xv");
01535 bool use_shm = (renderer == "xshm");
01536 bool use_opengl = (renderer == "opengl");
01537 bool ok = InitVideoBuffers(myth_codec_id, use_xv, use_shm, use_opengl);
01538 if (!ok)
01539 {
01540 use_xv = renderers.contains("xv-blit");
01541 use_shm = renderers.contains("xshm");
01542 use_opengl = renderers.contains("opengl");
01543 ok = InitVideoBuffers(myth_codec_id, use_xv, use_shm, use_opengl);
01544 }
01545 XV_INIT_FATAL_ERROR_TEST(!ok, "Failed to get any video output");
01546
01547 QString osdrenderer = db_vdisp_profile->GetOSDRenderer();
01548
01549
01550 InitOSD(osdrenderer);
01551
01552
01553 if (!xvmc_tex && video_output_subtype >= XVideo)
01554 InitColorKey(true);
01555
01556
01557 if (!CheckOSDInit())
01558 {
01559 ok = InitVideoBuffers(myth_codec_id, use_xv, use_shm, use_opengl);
01560 XV_INIT_FATAL_ERROR_TEST(!ok, "Failed to get any video output (nCK)");
01561 }
01562
01563
01564 if (db_use_picture_controls)
01565 InitPictureAttributes();
01566
01567 return true;
01568 }
01569
01576 bool VideoOutputXv::Init(
01577 int width, int height, float aspect,
01578 WId winid, int winx, int winy, int winw, int winh, WId embedid)
01579 {
01580 needrepaint = true;
01581
01582 XV_INIT_FATAL_ERROR_TEST(winid <= 0, "Invalid Window ID.");
01583
01584 XJ_disp = MythXOpenDisplay();
01585 XV_INIT_FATAL_ERROR_TEST(!XJ_disp, "Failed to open display.");
01586
01587
01588 X11L;
01589 XJ_screen = DefaultScreenOfDisplay(XJ_disp);
01590 XJ_screen_num = DefaultScreen(XJ_disp);
01591 XJ_white = XWhitePixel(XJ_disp, XJ_screen_num);
01592 XJ_black = XBlackPixel(XJ_disp, XJ_screen_num);
01593 XJ_curwin = winid;
01594 XJ_win = winid;
01595 XJ_root = DefaultRootWindow(XJ_disp);
01596 XJ_gc = XCreateGC(XJ_disp, XJ_win, 0, 0);
01597 XJ_depth = DefaultDepthOfScreen(XJ_screen);
01598
01599
01600 XJ_letterbox_colour = XJ_black;
01601 Colormap cmap = XDefaultColormap(XJ_disp, XJ_screen_num);
01602 XColor colour, colour_exact;
01603 QString name = toXString(db_letterbox_colour);
01604 if (XAllocNamedColor(XJ_disp, cmap, name.ascii(), &colour, &colour_exact))
01605 XJ_letterbox_colour = colour.pixel;
01606
01607 X11U;
01608
01609
01610 VideoOutput::Init(width, height, aspect,
01611 winid, winx, winy, winw, winh,
01612 embedid);
01613
01614
01615 InitDisplayMeasurements(width, height);
01616
01617
01618 if (embedid > 0)
01619 XJ_curwin = XJ_win = embedid;
01620
01621 if (!InitSetupBuffers())
01622 return false;
01623
01624 MoveResize();
01625
01626 XJ_started = true;
01627
01628 return true;
01629 }
01630 #undef XV_INIT_FATAL_ERROR_TEST
01631
01638 void VideoOutputXv::InitColorKey(bool turnoffautopaint)
01639 {
01640 static const char *attr_autopaint = "XV_AUTOPAINT_COLORKEY";
01641 int xv_val=0;
01642
01643
01644
01645 xv_draw_colorkey = true;
01646 if (xv_is_attrib_supported(XJ_disp, xv_port, attr_autopaint, &xv_val))
01647 {
01648 if (turnoffautopaint && xv_val)
01649 {
01650 xv_set_attrib(XJ_disp, xv_port, attr_autopaint, 0);
01651 if (!xv_get_attrib(XJ_disp, xv_port, attr_autopaint, xv_val) ||
01652 xv_val)
01653 {
01654 VERBOSE(VB_IMPORTANT, "Failed to disable autopaint");
01655 xv_draw_colorkey = false;
01656 }
01657 }
01658 else if (!turnoffautopaint && !xv_val)
01659 {
01660 xv_set_attrib(XJ_disp, xv_port, attr_autopaint, 1);
01661 if (!xv_get_attrib(XJ_disp, xv_port, attr_autopaint, xv_val) ||
01662 !xv_val)
01663 {
01664 VERBOSE(VB_IMPORTANT, "Failed to enable autopaint");
01665 }
01666 }
01667 else if (!turnoffautopaint && xv_val)
01668 {
01669 xv_draw_colorkey = false;
01670 }
01671 }
01672
01673
01674
01675
01676
01677 int letterbox_color = 0;
01678 static const char *attr_chroma = "XV_COLORKEY";
01679 if (!xv_is_attrib_supported(XJ_disp, xv_port, attr_chroma, &xv_colorkey))
01680 {
01681
01682 xv_colorkey = letterbox_color;
01683 }
01684 else if (xv_colorkey == letterbox_color)
01685 {
01686
01687 xv_set_attrib(XJ_disp, xv_port, attr_chroma, 1);
01688
01689 if (xv_get_attrib(XJ_disp, xv_port, attr_chroma, xv_val) &&
01690 xv_val != letterbox_color)
01691 {
01692 xv_colorkey = xv_val;
01693 }
01694 }
01695
01696 if (xv_colorkey == letterbox_color)
01697 {
01698 VERBOSE(VB_PLAYBACK, LOC +
01699 "Chromakeying not possible with this XVideo port.");
01700 }
01701 }
01702
01703
01704 bool VideoOutputXv::SetDeinterlacingEnabled(bool enable)
01705 {
01706 if (VideoOutputSubType() == OpenGL)
01707 return SetDeinterlacingEnabledOpenGL(enable);
01708
01709 bool deint = VideoOutput::SetDeinterlacingEnabled(enable);
01710 xv_need_bobdeint_repaint = (m_deintfiltername == "bobdeint");
01711 return deint;
01712 }
01713
01714 bool VideoOutputXv::SetupDeinterlace(bool interlaced,
01715 const QString& overridefilter)
01716 {
01717 if (VideoOutputSubType() == OpenGL)
01718 return SetupDeinterlaceOpenGL(interlaced, overridefilter);
01719
01720 bool deint = VideoOutput::SetupDeinterlace(interlaced, overridefilter);
01721 needrepaint = true;
01722 return deint;
01723 }
01724
01725 bool VideoOutputXv::SetDeinterlacingEnabledOpenGL(bool enable)
01726 {
01727 (void) enable;
01728
01729 if (!gl_videochain)
01730 return false;
01731
01732 if (enable && m_deinterlacing && (OpenGL != VideoOutputSubType()))
01733 return m_deinterlacing;
01734
01735 if (enable)
01736 {
01737 if (m_deintfiltername == "")
01738 return SetupDeinterlace(enable);
01739 if (m_deintfiltername.contains("opengl"))
01740 {
01741 if (gl_videochain->GetDeinterlacer() == "")
01742 return SetupDeinterlace(enable);
01743 }
01744 else if (!m_deintfiltername.contains("opengl"))
01745 {
01746
01747 gl_context_lock.lock();
01748 gl_videochain->SetDeinterlacing(false);
01749 gl_context_lock.unlock();
01750
01751 if (!m_deintFiltMan || !m_deintFilter)
01752 return VideoOutput::SetupDeinterlace(enable);
01753 }
01754 }
01755
01756 if (gl_videochain)
01757 {
01758 QMutexLocker locker(&gl_context_lock);
01759 gl_videochain->SetDeinterlacing(enable);
01760 }
01761
01762 m_deinterlacing = enable;
01763
01764 return m_deinterlacing;
01765 }
01766
01767 bool VideoOutputXv::SetupDeinterlaceOpenGL(
01768 bool interlaced, const QString &overridefilter)
01769 {
01770 (void) interlaced;
01771 (void) overridefilter;
01772
01773 m_deintfiltername = db_vdisp_profile->GetFilteredDeint(overridefilter);
01774
01775 if (!m_deintfiltername.contains("opengl"))
01776 {
01777 gl_context_lock.lock();
01778 gl_videochain->SetDeinterlacing(false);
01779 gl_context_lock.unlock();
01780
01781 gl_videochain->SetSoftwareDeinterlacer(QString::null);
01782
01783 VideoOutput::SetupDeinterlace(interlaced, overridefilter);
01784 if (m_deinterlacing)
01785 gl_videochain->SetSoftwareDeinterlacer(m_deintfiltername);
01786
01787 return m_deinterlacing;
01788 }
01789
01790
01791 if (m_deintFiltMan)
01792 {
01793 delete m_deintFiltMan;
01794 m_deintFiltMan = NULL;
01795 }
01796 if (m_deintFilter)
01797 {
01798 delete m_deintFilter;
01799 m_deintFilter = NULL;
01800 }
01801
01802 if (m_deinterlacing == interlaced && (OpenGL != VideoOutputSubType()))
01803 return m_deinterlacing;
01804 m_deinterlacing = interlaced;
01805
01806 if (!gl_videochain)
01807 return false;
01808
01809 QMutexLocker locker(&gl_context_lock);
01810
01811 if (m_deinterlacing && !m_deintfiltername.isEmpty())
01812 {
01813 if (gl_videochain->GetDeinterlacer() != m_deintfiltername)
01814 {
01815 if (!gl_videochain->AddDeinterlacer(m_deintfiltername))
01816 {
01817 VERBOSE(VB_IMPORTANT, LOC +
01818 QString("Couldn't load deinterlace filter %1")
01819 .arg(m_deintfiltername));
01820 m_deinterlacing = false;
01821 m_deintfiltername = "";
01822 }
01823 else
01824 {
01825 VERBOSE(VB_PLAYBACK, LOC +
01826 QString("Using deinterlace method %1")
01827 .arg(m_deintfiltername));
01828 }
01829 }
01830 }
01831
01832 gl_videochain->SetDeinterlacing(m_deinterlacing);
01833
01834 return m_deinterlacing;
01835 }
01836
01846 bool VideoOutputXv::ApproveDeintFilter(const QString& filtername) const
01847 {
01848
01849 VOSType vos = VideoOutputSubType();
01850 if (filtername == "bobdeint" && (vos >= XVideo || vos == OpenGL))
01851 return true;
01852 else if (vos > XVideo)
01853 return false;
01854 else
01855 return VideoOutput::ApproveDeintFilter(filtername);
01856 }
01857
01858 XvMCContext* VideoOutputXv::CreateXvMCContext(
01859 Display* disp, int port, int surf_type, int width, int height)
01860 {
01861 (void)disp; (void)port; (void)surf_type; (void)width; (void)height;
01862 #ifdef USING_XVMC
01863 int ret = Success;
01864 XvMCContext *ctx = new XvMCContext;
01865 X11S(ret = XvMCCreateContext(disp, port, surf_type, width, height,
01866 XVMC_DIRECT, ctx));
01867 if (ret != Success)
01868 {
01869 VERBOSE(VB_IMPORTANT, LOC_ERR +
01870 QString("Unable to create XvMC Context, status(%1): %2")
01871 .arg(ret).arg(ErrorStringXvMC(ret)));
01872
01873 delete ctx;
01874 ctx = NULL;
01875 }
01876 return ctx;
01877 #else // if !USING_XVMC
01878 return NULL;
01879 #endif // !USING_XVMC
01880 }
01881
01882 void VideoOutputXv::DeleteXvMCContext(Display* disp, XvMCContext*& ctx)
01883 {
01884 (void)disp; (void)ctx;
01885 #ifdef USING_XVMC
01886 if (ctx)
01887 {
01888 X11S(XvMCDestroyContext(disp, ctx));
01889 delete ctx;
01890 ctx = NULL;
01891 }
01892 #endif // !USING_XVMC
01893 }
01894
01895 bool VideoOutputXv::CreateXvMCBuffers(void)
01896 {
01897 #ifdef USING_XVMC
01898 xvmc_ctx = CreateXvMCContext(XJ_disp, xv_port,
01899 xvmc_surf_info.surface_type_id,
01900 video_dim.width(), video_dim.height());
01901 if (!xvmc_ctx)
01902 return false;
01903
01904 bool surface_has_vld = (XVMC_VLD == (xvmc_surf_info.mc_type & XVMC_VLD));
01905 xvmc_surfs = CreateXvMCSurfaces(xvmc_buf_attr->GetMaxSurf(),
01906 surface_has_vld);
01907
01908 if (xvmc_surfs.size() < xvmc_buf_attr->GetMinSurf())
01909 {
01910 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create XvMC Surfaces");
01911 DeleteBuffers(XVideoMC, false);
01912 return false;
01913 }
01914
01915 bool ok = vbuffers.CreateBuffers(video_dim.width(), video_dim.height(),
01916 XJ_disp, xvmc_ctx,
01917 &xvmc_surf_info, xvmc_surfs);
01918 if (!ok)
01919 {
01920 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unable to create XvMC Buffers");
01921 DeleteBuffers(XVideoMC, false);
01922 return false;
01923 }
01924
01925 xvmc_osd_lock.lock();
01926 for (uint i=0; i < xvmc_buf_attr->GetOSDNum(); i++)
01927 {
01928 XvMCOSD *xvmc_osd =
01929 new XvMCOSD(XJ_disp, xv_port, xvmc_surf_info.surface_type_id,
01930 xvmc_surf_info.flags);
01931 xvmc_osd->CreateBuffer(*xvmc_ctx,
01932 video_dim.width(), video_dim.height());
01933 xvmc_osd_available.push_back(xvmc_osd);
01934 }
01935 xvmc_osd_lock.unlock();
01936
01937
01938 X11S(XSync(XJ_disp, False));
01939
01940 return true;
01941 #else
01942 return false;
01943 #endif // USING_XVMC
01944 }
01945
01946 vector<void*> VideoOutputXv::CreateXvMCSurfaces(uint num, bool surface_has_vld)
01947 {
01948 (void)num;
01949 (void)surface_has_vld;
01950
01951 vector<void*> surfaces;
01952 #ifdef USING_XVMC
01953 uint blocks_per_macroblock = calcBPM(xvmc_chroma);
01954 uint num_mv_blocks = (((video_dim.width() + 15) / 16) *
01955 ((video_dim.height() + 15) / 16));
01956 uint num_data_blocks = num_mv_blocks * blocks_per_macroblock;
01957
01958
01959 if (surface_has_vld)
01960 num += 5;
01961
01962
01963 bool ok = true;
01964 for (uint i = 0; i < num; i++)
01965 {
01966 xvmc_vo_surf_t *surf = new xvmc_vo_surf_t;
01967 bzero(surf, sizeof(xvmc_vo_surf_t));
01968
01969 X11L;
01970
01971 int ret = XvMCCreateSurface(XJ_disp, xvmc_ctx, &(surf->surface));
01972 ok &= (Success == ret);
01973
01974 if (ok && !surface_has_vld)
01975 {
01976 ret = XvMCCreateBlocks(XJ_disp, xvmc_ctx, num_data_blocks,
01977 &(surf->blocks));
01978 if (Success != ret)
01979 {
01980 XvMCDestroySurface(XJ_disp, &(surf->surface));
01981 ok = false;
01982 }
01983 }
01984
01985 if (ok && !surface_has_vld)
01986 {
01987 ret = XvMCCreateMacroBlocks(XJ_disp, xvmc_ctx, num_mv_blocks,
01988 &(surf->macro_blocks));
01989 if (Success != ret)
01990 {
01991 XvMCDestroyBlocks(XJ_disp, &(surf->blocks));
01992 XvMCDestroySurface(XJ_disp, &(surf->surface));
01993 ok = false;
01994 }
01995 }
01996
01997 X11U;
01998
01999 if (!ok)
02000 {
02001 delete surf;
02002 break;
02003 }
02004 surfaces.push_back(surf);
02005 }
02006
02007
02008
02009
02010 if (surface_has_vld)
02011 {
02012 VERBOSE(VB_PLAYBACK, LOC +
02013 QString("VLD - Allocated %1 surfaces, "
02014 "now destroying 5 of them.").arg(surfaces.size()));
02015
02016 for (uint i = 0; i < 5; i++)
02017 {
02018 xvmc_vo_surf_t *surf = (xvmc_vo_surf_t*)surfaces.back();
02019 surfaces.pop_back();
02020 XvMCDestroySurface(XJ_disp, &(surf->surface));
02021 delete surf;
02022 }
02023 }
02024 #endif // USING_XVMC
02025 return surfaces;
02026 }
02027
02039 vector<unsigned char*> VideoOutputXv::CreateShmImages(uint num, bool use_xv)
02040 {
02041 VERBOSE(VB_PLAYBACK, LOC +
02042 QString("CreateShmImages(%1): video_dim: %2x%3")
02043 .arg(num).arg(video_dim.width()).arg(video_dim.height()));
02044
02045 vector<unsigned char*> bufs;
02046 for (uint i = 0; i < num; i++)
02047 {
02048 XShmSegmentInfo *info = new XShmSegmentInfo;
02049 void *image = NULL;
02050 int size = 0;
02051 int desiredsize = 0;
02052
02053 X11L;
02054
02055 if (use_xv)
02056 {
02057 XvImage *img =
02058 XvShmCreateImage(XJ_disp, xv_port, xv_chroma, 0,
02059 video_dim.width(), video_dim.height(), info);
02060 size = img->data_size + 64;
02061 image = img;
02062 desiredsize = video_dim.width() * video_dim.height() * 3 / 2;
02063
02064 if (image && size < desiredsize)
02065 {
02066 VERBOSE(VB_IMPORTANT, LOC_ERR + "CreateXvShmImages(): "
02067 "XvShmCreateImage() failed to create image of the "
02068 "requested size.");
02069 XFree(image);
02070 image = NULL;
02071 delete info;
02072 }
02073
02074 if (image && (3 == img->num_planes))
02075 {
02076 XJ_shm_infos.push_back(info);
02077 YUVInfo tmp(img->width, img->height, img->data_size,
02078 img->pitches, img->offsets);
02079 if (xv_chroma == GUID_YV12_PLANAR)
02080 {
02081 swap(tmp.pitches[1], tmp.pitches[2]);
02082 swap(tmp.offsets[1], tmp.offsets[2]);
02083 }
02084
02085 XJ_yuv_infos.push_back(tmp);
02086 }
02087 else if (image)
02088 {
02089 VERBOSE(VB_IMPORTANT, LOC_ERR + "CreateXvShmImages(): "
02090 "XvShmCreateImage() failed to create image "
02091 "with the correct number of pixel planes.");
02092 XFree(image);
02093 image = NULL;
02094 delete info;
02095 }
02096 }
02097 else
02098 {
02099 XImage *img =
02100 XShmCreateImage(XJ_disp, DefaultVisual(XJ_disp, XJ_screen_num),
02101 XJ_depth, ZPixmap, 0, info,
02102 display_visible_rect.width(),
02103 display_visible_rect.height());
02104 size = img->bytes_per_line * img->height + 64;
02105 image = img;
02106 desiredsize = (display_visible_rect.width() *
02107 display_visible_rect.height() * 3 / 2);
02108 if (image && size < desiredsize)
02109 {
02110 VERBOSE(VB_IMPORTANT, LOC_ERR + "CreateXvShmImages(): "
02111 "XShmCreateImage() failed to create image of the "
02112 "requested size.");
02113 XDestroyImage((XImage *)image);
02114 image = NULL;
02115 delete info;
02116 }
02117
02118 if (image)
02119 {
02120 YUVInfo tmp(img->width, img->height,
02121 img->bytes_per_line * img->height, NULL, NULL);
02122 XJ_yuv_infos.push_back(tmp);
02123 XJ_shm_infos.push_back(info);
02124 }
02125 }
02126
02127 X11U;
02128
02129 if (image)
02130 {
02131 XJ_shm_infos[i]->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0777);
02132 if (XJ_shm_infos[i]->shmid >= 0)
02133 {
02134 XJ_shm_infos[i]->shmaddr = (char*)
02135 shmat(XJ_shm_infos[i]->shmid, 0, 0);
02136 if (use_xv)
02137 ((XvImage*)image)->data = XJ_shm_infos[i]->shmaddr;
02138 else
02139 ((XImage*)image)->data = XJ_shm_infos[i]->shmaddr;
02140 xv_buffers[(unsigned char*) XJ_shm_infos[i]->shmaddr] = image;
02141 XJ_shm_infos[i]->readOnly = False;
02142
02143 X11L;
02144 XShmAttach(XJ_disp, XJ_shm_infos[i]);
02145 XSync(XJ_disp, False);
02146 X11U;
02147
02148
02149
02150 shmctl(XJ_shm_infos[i]->shmid, IPC_RMID, 0);
02151
02152 bufs.push_back((unsigned char*) XJ_shm_infos[i]->shmaddr);
02153 }
02154 else
02155 {
02156 VERBOSE(VB_IMPORTANT, LOC_ERR +
02157 "CreateXvShmImages(): shmget() failed." + ENO);
02158 break;
02159 }
02160 }
02161 else
02162 {
02163 VERBOSE(VB_IMPORTANT, LOC_ERR + "CreateXvShmImages(): "
02164 "XvShmCreateImage() failed to create image.");
02165 break;
02166 }
02167 }
02168 return bufs;
02169 }
02170
02171 bool VideoOutputXv::CreateBuffers(VOSType subtype)
02172 {
02173 bool ok = false;
02174
02175 if (subtype > XVideo && xv_port >= 0)
02176 ok = CreateXvMCBuffers();
02177 else if (subtype == XVideo && xv_port >= 0)
02178 {
02179 vector<unsigned char*> bufs =
02180 CreateShmImages(vbuffers.allocSize(), true);
02181
02182 ok = (bufs.size() >= vbuffers.allocSize()) &&
02183 vbuffers.CreateBuffers(video_dim.width(), video_dim.height(),
02184 bufs, XJ_yuv_infos);
02185
02186 X11S(XSync(XJ_disp, False));
02187 }
02188 else if (subtype == XShm || subtype == Xlib)
02189 {
02190 if (subtype == XShm)
02191 {
02192 vector<unsigned char*> bufs = CreateShmImages(1, false);
02193 if (bufs.empty())
02194 return false;
02195 XJ_non_xv_image = (XImage*) xv_buffers.begin()->second;
02196 }
02197 else
02198 {
02199
02200 X11L;
02201
02202 int bytes_per_line = XJ_depth / 8 * display_visible_rect.width();
02203 int scrn = DefaultScreen(XJ_disp);
02204 Visual *visual = DefaultVisual(XJ_disp, scrn);
02205 XJ_non_xv_image = XCreateImage(XJ_disp, visual, XJ_depth,
02206 ZPixmap, 0, 0,
02207 display_visible_rect.width(),
02208 display_visible_rect.height(),
02209 0,
02210 bytes_per_line);
02211
02212 X11U;
02213
02214 if (!XJ_non_xv_image)
02215 {
02216 VERBOSE(VB_IMPORTANT, LOC_ERR + "XCreateImage failed: "
02217 <<"XJ_disp("<<XJ_disp<<") visual("<<visual<<") "<<endl
02218 <<" "
02219 <<"XJ_depth("<<XJ_depth<<") "
02220 <<"WxH("<<display_visible_rect.width()
02221 <<"x"<<display_visible_rect.height()<<") "
02222 <<"bpl("<<bytes_per_line<<")");
02223 return false;
02224 }
02225 XJ_non_xv_image->data = (char*) malloc(
02226 bytes_per_line * display_visible_rect.height());
02227 }
02228
02229 switch (XJ_non_xv_image->bits_per_pixel)
02230 {
02231 case 16: non_xv_av_format = PIX_FMT_RGB565; break;
02232 case 24: non_xv_av_format = PIX_FMT_RGB24; break;
02233 case 32: non_xv_av_format = PIX_FMT_RGBA32; break;
02234 default: non_xv_av_format = PIX_FMT_NB;
02235 }
02236 if (PIX_FMT_NB == non_xv_av_format)
02237 {
02238 QString msg = QString(
02239 "Non XVideo modes only support displays with 16,\n\t\t\t"
02240 "24, or 32 bits per pixel. But you have a %1 bpp display.")
02241 .arg(XJ_depth*8);
02242
02243 VERBOSE(VB_IMPORTANT, LOC_ERR + msg);
02244 }
02245 else
02246 ok = vbuffers.CreateBuffers(video_dim.width(), video_dim.height());
02247 }
02248 else if (subtype == OpenGL)
02249 {
02250 QSize size = gl_videochain->GetVideoSize();
02251 ok = vbuffers.CreateBuffers(size.width(), size.height());
02252 }
02253
02254 if (ok)
02255 CreatePauseFrame(subtype);
02256
02257 return ok;
02258 }
02259
02260 void VideoOutputXv::DeleteBuffers(VOSType subtype, bool delete_pause_frame)
02261 {
02262 (void) subtype;
02263 DiscardFrames(true);
02264
02265 #ifdef USING_XVMC
02266
02267 for (uint i=0; i<xvmc_surfs.size(); i++)
02268 {
02269 xvmc_vo_surf_t *surf = (xvmc_vo_surf_t*) xvmc_surfs[i];
02270 X11S(XvMCHideSurface(XJ_disp, &(surf->surface)));
02271 }
02272 DiscardFrames(true);
02273 for (uint i=0; i<xvmc_surfs.size(); i++)
02274 {
02275 xvmc_vo_surf_t *surf = (xvmc_vo_surf_t*) xvmc_surfs[i];
02276
02277 X11L;
02278
02279 XvMCDestroySurface(XJ_disp, &(surf->surface));
02280 XvMCDestroyMacroBlocks(XJ_disp, &(surf->macro_blocks));
02281 XvMCDestroyBlocks(XJ_disp, &(surf->blocks));
02282
02283 X11U;
02284 }
02285 xvmc_surfs.clear();
02286
02287
02288 xvmc_osd_lock.lock();
02289 for (uint i=0; i<xvmc_osd_available.size(); i++)
02290 {
02291 xvmc_osd_available[i]->DeleteBuffer();
02292 delete xvmc_osd_available[i];
02293 }
02294 xvmc_osd_available.clear();
02295 xvmc_osd_lock.unlock();
02296
02297 if (xvmc_tex)
02298 {
02299 delete xvmc_tex;
02300 xvmc_tex = NULL;
02301 }
02302 #endif // USING_XVMC
02303
02304
02305 gl_context_lock.lock();
02306
02307 if (gl_videochain)
02308 {
02309 delete gl_videochain;
02310 gl_videochain = NULL;
02311 }
02312 if (gl_pipchain)
02313 {
02314 delete gl_pipchain;
02315 gl_pipchain = NULL;
02316 }
02317 if (gl_osdchain)
02318 {
02319 delete gl_osdchain;
02320 gl_osdchain = NULL;
02321 }
02322 #ifdef USING_OPENGL
02323 if (gl_context)
02324 gl_context->Hide();
02325 #endif
02326 gl_use_osd_opengl2 = false;
02327 gl_pip_ready = false;
02328 gl_osd_ready = false;
02329 allowpreviewepg = true;
02330
02331 gl_context_lock.unlock();
02332
02333
02334 vbuffers.DeleteBuffers();
02335
02336 if (delete_pause_frame)
02337 {
02338 if (av_pause_frame.buf)
02339 {
02340 delete [] av_pause_frame.buf;
02341 av_pause_frame.buf = NULL;
02342 }
02343 if (av_pause_frame.qscale_table)
02344 {
02345 delete [] av_pause_frame.qscale_table;
02346 av_pause_frame.qscale_table = NULL;
02347 }
02348 }
02349
02350 for (uint i = 0; i < XJ_shm_infos.size(); i++)
02351 {
02352 X11S(XShmDetach(XJ_disp, XJ_shm_infos[i]));
02353 XvImage *image = (XvImage*)
02354 xv_buffers[(unsigned char*) XJ_shm_infos[i]->shmaddr];
02355 if (image)
02356 {
02357 if ((XImage*)image == (XImage*)XJ_non_xv_image)
02358 X11S(XDestroyImage((XImage*)XJ_non_xv_image));
02359 else
02360 X11S(XFree(image));
02361 }
02362 if (XJ_shm_infos[i]->shmaddr)
02363 shmdt(XJ_shm_infos[i]->shmaddr);
02364 if (XJ_shm_infos[i]->shmid > 0)
02365 shmctl(XJ_shm_infos[i]->shmid, IPC_RMID, 0);
02366 delete XJ_shm_infos[i];
02367 }
02368 XJ_shm_infos.clear();
02369 xv_buffers.clear();
02370 XJ_yuv_infos.clear();
02371 XJ_non_xv_image = NULL;
02372
02373 #ifdef USING_XVMC
02374 DeleteXvMCContext(XJ_disp, xvmc_ctx);
02375 #endif // USING_XVMC
02376 }
02377
02378 void VideoOutputXv::EmbedInWidget(WId wid, int x, int y, int w, int h)
02379 {
02380 QMutexLocker locker(&global_lock);
02381
02382 if (embedding)
02383 {
02384 MoveResize();
02385 return;
02386 }
02387
02388 XJ_curwin = wid;
02389
02390 VideoOutput::EmbedInWidget(wid, x, y, w, h);
02391 }
02392
02393 void VideoOutputXv::StopEmbedding(void)
02394 {
02395 if (!embedding)
02396 return;
02397
02398 QMutexLocker locker(&global_lock);
02399
02400 XJ_curwin = XJ_win;
02401 VideoOutput::StopEmbedding();
02402 }
02403
02404 VideoFrame *VideoOutputXv::GetNextFreeFrame(bool )
02405 {
02406 return vbuffers.GetNextFreeFrame(false, false);
02407 }
02408
02416 void VideoOutputXv::DiscardFrame(VideoFrame *frame)
02417 {
02418 bool displaying = false;
02419 if (!frame)
02420 return;
02421
02422 #ifdef USING_XVMC
02423 vbuffers.LockFrame(frame, "DiscardFrame -- XvMC display check");
02424 if (frame && VideoOutputSubType() >= XVideoMC)
02425 {
02426
02427 VideoFrame* pframe = NULL;
02428 VideoFrame* osdframe = NULL;
02429 if (xvmc_buf_attr->GetOSDNum())
02430 osdframe = vbuffers.GetOSDFrame(frame);
02431
02432 if (osdframe)
02433 vbuffers.SetOSDFrame(frame, NULL);
02434 else
02435 pframe = vbuffers.GetOSDParent(frame);
02436
02437 SyncSurface(frame);
02438 displaying = IsDisplaying(frame);
02439 vbuffers.UnlockFrame(frame, "DiscardFrame -- XvMC display check A");
02440
02441 SyncSurface(osdframe);
02442 displaying |= IsDisplaying(osdframe);
02443
02444 if (!displaying && pframe)
02445 vbuffers.SetOSDFrame(frame, NULL);
02446 }
02447 else
02448 vbuffers.UnlockFrame(frame, "DiscardFrame -- XvMC display check B");
02449 #endif
02450
02451 if (displaying || vbuffers.HasChildren(frame))
02452 vbuffers.safeEnqueue(kVideoBuffer_displayed, frame);
02453 else
02454 {
02455 vbuffers.LockFrame(frame, "DiscardFrame -- XvMC not displaying");
02456 #ifdef USING_XVMC
02457 if (frame && VideoOutputSubType() >= XVideoMC)
02458 {
02459 GetRender(frame)->p_past_surface = NULL;
02460 GetRender(frame)->p_future_surface = NULL;
02461 }
02462 #endif
02463 vbuffers.UnlockFrame(frame, "DiscardFrame -- XvMC not displaying");
02464 vbuffers.RemoveInheritence(frame);
02465 vbuffers.DiscardFrame(frame);
02466 }
02467 }
02468
02469 void VideoOutputXv::ClearAfterSeek(void)
02470 {
02471 VERBOSE(VB_PLAYBACK, LOC + "ClearAfterSeek()");
02472 DiscardFrames(false);
02473 #ifdef USING_XVMC
02474 if (VideoOutputSubType() > XVideo)
02475 {
02476 for (uint i=0; i<xvmc_surfs.size(); i++)
02477 {
02478 xvmc_vo_surf_t *surf = (xvmc_vo_surf_t*) xvmc_surfs[i];
02479 X11S(XvMCHideSurface(XJ_disp, &(surf->surface)));
02480 }
02481 DiscardFrames(true);
02482 }
02483 #endif
02484 }
02485
02486 #define DQ_COPY(DST, SRC) \
02487 do { \
02488 DST.insert(DST.end(), vbuffers.begin_lock(SRC), vbuffers.end(SRC)); \
02489 vbuffers.end_lock(); \
02490 } while (0)
02491
02492 void VideoOutputXv::DiscardFrames(bool next_frame_keyframe)
02493 {
02494 VERBOSE(VB_PLAYBACK, LOC + "DiscardFrames("<<next_frame_keyframe<<")");
02495 if (VideoOutputSubType() <= XVideo)
02496 {
02497 vbuffers.DiscardFrames(next_frame_keyframe);
02498 VERBOSE(VB_PLAYBACK, LOC + QString("DiscardFrames() 3: %1 -- done()")
02499 .arg(vbuffers.GetStatus()));
02500 return;
02501 }
02502
02503 #ifdef USING_XVMC
02504 frame_queue_t::iterator it;
02505 frame_queue_t syncs;
02506
02507
02508 vbuffers.begin_lock(kVideoBuffer_displayed);
02509 VERBOSE(VB_PLAYBACK, LOC + QString("DiscardFrames() 1: %1")
02510 .arg(vbuffers.GetStatus()));
02511 vbuffers.end_lock();
02512
02513
02514
02515
02516
02517
02518
02519 vbuffers.begin_lock(kVideoBuffer_displayed);
02520 DQ_COPY(syncs, kVideoBuffer_used);
02521 for (it = syncs.begin(); it != syncs.end(); ++it)
02522 {
02523 SyncSurface(*it, -1);
02524 SyncSurface(*it, +1);
02525 SyncSurface(*it, 0);
02526 vbuffers.safeEnqueue(kVideoBuffer_displayed, *it);
02527 }
02528 syncs.clear();
02529 vbuffers.end_lock();
02530
02531 CheckFrameStates();
02532
02533
02534 if (next_frame_keyframe)
02535 {
02536 vbuffers.begin_lock(kVideoBuffer_displayed);
02537
02538
02539 DQ_COPY(syncs, kVideoBuffer_limbo);
02540 for (it = syncs.begin(); it != syncs.end(); ++it)
02541 {
02542 SyncSurface(*it, -1);
02543 SyncSurface(*it, +1);
02544 SyncSurface(*it, 0);
02545 vbuffers.safeEnqueue(kVideoBuffer_displayed, *it);
02546 }
02547
02548 VERBOSE(VB_PLAYBACK, LOC + QString("DiscardFrames() 2: %1")
02549 .arg(vbuffers.GetStatus()));
02550
02551 vbuffers.end_lock();
02552
02553
02554
02555
02556
02557 CheckFrameStates();
02558 }
02559 VERBOSE(VB_PLAYBACK, LOC + QString("DiscardFrames() 3: %1 -- done()")
02560 .arg(vbuffers.GetStatus()));
02561
02562 #endif // USING_XVMC
02563 }
02564
02565 #undef DQ_COPY
02566
02582 void VideoOutputXv::DoneDisplayingFrame(void)
02583 {
02584 if (VideoOutputSubType() <= XVideo || xvmc_tex)
02585 {
02586 vbuffers.DoneDisplayingFrame();
02587 return;
02588 }
02589 #ifdef USING_XVMC
02590 if (vbuffers.size(kVideoBuffer_used))
02591 {
02592 VideoFrame *frame = vbuffers.head(kVideoBuffer_used);
02593 DiscardFrame(frame);
02594
02595 VideoFrame *osdframe = NULL;
02596 if (xvmc_buf_attr->GetOSDNum())
02597 osdframe = vbuffers.GetOSDFrame(frame);
02598
02599 if (osdframe)
02600 DiscardFrame(osdframe);
02601 }
02602 CheckFrameStates();
02603 #endif
02604 }
02605
02611 void VideoOutputXv::PrepareFrameXvMC(VideoFrame *frame, FrameScanType scan)
02612 {
02613 (void)frame;
02614 (void)scan;
02615 #ifdef USING_XVMC
02616 xvmc_render_state_t *render = NULL, *osdrender = NULL;
02617 VideoFrame *osdframe = NULL;
02618
02619 if (frame)
02620 {
02621 global_lock.lock();
02622 framesPlayed = frame->frameNumber + 1;
02623 global_lock.unlock();
02624
02625 vbuffers.LockFrame(frame, "PrepareFrameXvMC");
02626 SyncSurface(frame);
02627 render = GetRender(frame);
02628 render->state |= MP_XVMC_STATE_DISPLAY_PENDING;
02629 if (xvmc_tex)
02630 xvmc_tex->PrepareFrame(render->p_surface,display_video_rect,scan);
02631 else if (xvmc_buf_attr->GetOSDNum())
02632 osdframe = vbuffers.GetOSDFrame(frame);
02633 vbuffers.UnlockFrame(frame, "PrepareFrameXvMC");
02634 }
02635
02636 if (osdframe)
02637 {
02638 vbuffers.LockFrame(osdframe, "PrepareFrameXvMC -- osd");
02639 SyncSurface(osdframe);
02640 osdrender = GetRender(osdframe);
02641 osdrender->state |= MP_XVMC_STATE_DISPLAY_PENDING;
02642 vbuffers.UnlockFrame(osdframe, "PrepareFrameXvMC -- osd");
02643 }
02644 #endif // USING_XVMC
02645 }
02646
02652 void VideoOutputXv::PrepareFrameXv(VideoFrame *frame)
02653 {
02654 if (!frame)
02655 frame = vbuffers.GetScratchFrame();
02656
02657 XvImage *image = NULL;
02658 {
02659 QMutexLocker locker(&global_lock);
02660 vbuffers.LockFrame(frame, "PrepareFrameXv");
02661 framesPlayed = frame->frameNumber + 1;
02662 image = (XvImage*) xv_buffers[frame->buf];
02663 vbuffers.UnlockFrame(frame, "PrepareFrameXv");
02664 }
02665
02666 if (vbuffers.GetScratchFrame() == frame)
02667 vbuffers.SetLastShownFrameToScratch();
02668 }
02669
02670 void VideoOutputXv::PrepareFrameOpenGL(VideoFrame *buffer, FrameScanType t)
02671 {
02672 (void) t;
02673
02674 QMutexLocker locker(&gl_context_lock);
02675
02676 if (!buffer)
02677 buffer = vbuffers.GetScratchFrame();
02678
02679 framesPlayed = buffer->frameNumber + 1;
02680
02681
02682 if (buffer->codec != FMT_YV12)
02683 return;
02684
02685 gl_context->MakeCurrent(true);
02686 gl_videochain->PrepareFrame(t, m_deinterlacing, framesPlayed);
02687
02688 if (gl_pip_ready && gl_pipchain)
02689 gl_pipchain->PrepareFrame(t, m_deinterlacing, framesPlayed);
02690
02691 if (gl_osd_ready && gl_osdchain)
02692 gl_osdchain->PrepareFrame(t, m_deinterlacing, framesPlayed);
02693
02694 gl_context->Flush();
02695 gl_context->MakeCurrent(false);
02696
02697 if (vbuffers.GetScratchFrame() == buffer)
02698 vbuffers.SetLastShownFrameToScratch();
02699 }
02700
02706 void VideoOutputXv::PrepareFrameMem(VideoFrame *buffer, FrameScanType )
02707 {
02708 if (!buffer)
02709 buffer = vbuffers.GetScratchFrame();
02710
02711 vbuffers.LockFrame(buffer, "PrepareFrameMem");
02712
02713 framesPlayed = buffer->frameNumber + 1;
02714 int width = buffer->width;
02715 int height = buffer->height;
02716
02717 vbuffers.UnlockFrame(buffer, "PrepareFrameMem");
02718
02719
02720
02721 if (non_xv_frames_shown == 0)
02722 non_xv_stop_time = time(NULL) + 4;
02723
02724 if ((!non_xv_fps) && (time(NULL) > non_xv_stop_time))
02725 {
02726 non_xv_fps = (int)(non_xv_frames_shown / 4);
02727
02728 if (non_xv_fps < 25)
02729 {
02730 non_xv_show_frame = 120 / non_xv_frames_shown + 1;
02731 VERBOSE(VB_IMPORTANT, LOC_ERR + "\n"
02732 "***\n"
02733 "* Your system is not capable of displaying the\n"
02734 "* full framerate at "
02735 <<display_visible_rect.width()<<"x"
02736 <<display_visible_rect.height()<<" resolution. Frames\n"
02737 "* will be skipped in order to keep the audio and\n"
02738 "* video in sync.\n");
02739 }
02740 }
02741
02742 non_xv_frames_shown++;
02743
02744 if ((non_xv_show_frame != 1) && (non_xv_frames_shown % non_xv_show_frame))
02745 return;
02746
02747 if (!XJ_non_xv_image)
02748 {
02749 VERBOSE(VB_IMPORTANT, LOC_ERR + "XJ_non_xv_image == NULL");
02750 return;
02751 }
02752
02753 unsigned char *sbuf = new unsigned char[
02754 display_visible_rect.width() * display_visible_rect.height() * 3 / 2];
02755 AVPicture image_in, image_out;
02756 ImgReSampleContext *scontext;
02757
02758 avpicture_fill(&image_out, (uint8_t *)sbuf, PIX_FMT_YUV420P,
02759 display_visible_rect.width(),
02760 display_visible_rect.height());
02761
02762 vbuffers.LockFrame(buffer, "PrepareFrameMem");
02763 if ((display_visible_rect.width() == width) &&
02764 (display_visible_rect.height() == height))
02765 {
02766 memcpy(sbuf, buffer->buf, width * height * 3 / 2);
02767 }
02768 else
02769 {
02770 avpicture_fill(&image_in, buffer->buf, PIX_FMT_YUV420P,
02771 width, height);
02772 scontext = img_resample_init(display_visible_rect.width(),
02773 display_visible_rect.height(),
02774 width, height);
02775 img_resample(scontext, &image_out, &image_in);
02776
02777 img_resample_close(scontext);
02778 }
02779 vbuffers.UnlockFrame(buffer, "PrepareFrameMem");
02780
02781 avpicture_fill(&image_in, (uint8_t *)XJ_non_xv_image->data,
02782 non_xv_av_format, display_visible_rect.width(),
02783 display_visible_rect.height());
02784
02785 img_convert(&image_in, non_xv_av_format, &image_out, PIX_FMT_YUV420P,
02786 display_visible_rect.width(), display_visible_rect.height());
02787
02788 {
02789 QMutexLocker locker(&global_lock);
02790 X11L;
02791 if (XShm == video_output_subtype)
02792 XShmPutImage(XJ_disp, XJ_curwin, XJ_gc, XJ_non_xv_image,
02793 0, 0, 0, 0, display_visible_rect.width(),
02794 display_visible_rect.height(), False);
02795 else
02796 XPutImage(XJ_disp, XJ_curwin, XJ_gc, XJ_non_xv_image,
02797 0, 0, 0, 0, display_visible_rect.width(),
02798 display_visible_rect.height());
02799 X11U;
02800 }
02801
02802 delete [] sbuf;
02803 }
02804
02805
02806 void VideoOutputXv::PrepareFrame(VideoFrame *buffer, FrameScanType scan)
02807 {
02808 if (IsErrored())
02809 {
02810 VERBOSE(VB_IMPORTANT, LOC_ERR + "IsErrored() in PrepareFrame()");
02811 return;
02812 }
02813
02814 if (VideoOutputSubType() > XVideo)
02815 PrepareFrameXvMC(buffer, scan);
02816 else if (VideoOutputSubType() == XVideo)
02817 PrepareFrameXv(buffer);
02818 else if (VideoOutputSubType() == OpenGL)
02819 PrepareFrameOpenGL(buffer, scan);
02820 else
02821 PrepareFrameMem(buffer, scan);
02822 }
02823
02824 static void calc_bob(FrameScanType scan, int imgh, int disphoff,
02825 int imgy, int dispyoff,
02826 int frame_height, int top_field_first,
02827 int &field, int &src_y, int &dest_y,
02828 int& xv_src_y_incr, int &xv_dest_y_incr)
02829 {
02830 int dst_half_line_in_src = 0, dest_y_incr = 0, src_y_incr = 0;
02831 field = 3;
02832 src_y = imgy;
02833 dest_y = dispyoff;
02834 xv_src_y_incr = 0;
02835
02836 if ((kScan_Interlaced != scan) && (kScan_Intr2ndField != scan))
02837 return;
02838
02839
02840 if (dispyoff < 0)
02841 {
02842 dest_y_incr = -dispyoff;
02843 src_y_incr = (int) (dest_y_incr * imgh / disphoff);
02844 xv_src_y_incr -= (int) (0.5 * dest_y_incr * imgh / disphoff);
02845 }
02846
02847 if ((scan == kScan_Interlaced && top_field_first == 1) ||
02848 (scan == kScan_Intr2ndField && top_field_first == 0))
02849 {
02850 field = 1;
02851 xv_src_y_incr += - imgy / 2;
02852 }
02853 else if ((scan == kScan_Interlaced && top_field_first == 0) ||
02854 (scan == kScan_Intr2ndField && top_field_first == 1))
02855 {
02856 field = 2;
02857 xv_src_y_incr += (frame_height - imgy) / 2;
02858
02859 dst_half_line_in_src =
02860 max((int) round((((double)disphoff)/imgh) - 0.00001), 0);
02861 }
02862 src_y += src_y_incr;
02863 dest_y += dest_y_incr;
02864
02865 #define NVIDIA_6629
02866 #ifdef NVIDIA_6629
02867 xv_dest_y_incr = dst_half_line_in_src;
02868
02869
02870 int mod = 0;
02871 if (frame_height>=(int)(imgh+(0.05*frame_height)) && 2==field)
02872 {
02873
02874 mod = -dst_half_line_in_src;
02875 dest_y += mod;
02876 xv_dest_y_incr -= mod;
02877 }
02878 #else
02879 dest_y += dst_half_line_in_src;
02880 #endif
02881
02882
02883 #if 0
02884 static int last_dest_y_field[3] = { -1000, -1000, -1000, };
02885 int last_dest_y = last_dest_y_field[field];
02886
02887 if (last_dest_y != dest_y)
02888 {
02889 cerr<<"####### Field "<<field<<" #######"<<endl;
02890 cerr<<" src_y: "<<src_y<<endl;
02891 cerr<<" dest_y: "<<dest_y<<endl;
02892 cerr<<" xv_src_y_incr: "<<xv_src_y_incr<<endl;
02893 cerr<<"xv_dest_y_incr: "<<xv_dest_y_incr<<endl;
02894 cerr<<" disphoff: "<<disphoff<<endl;
02895 cerr<<" imgh: "<<imgh<<endl;
02896 cerr<<" mod: "<<mod<<endl;
02897 cerr<<endl;
02898 }
02899 last_dest_y_field[field] = dest_y;
02900 #endif
02901 }
02902
02903 void VideoOutputXv::ShowXvMC(FrameScanType scan)
02904 {
02905 (void)scan;
02906 #ifdef USING_XVMC
02907 VideoFrame *frame = NULL;
02908 bool using_pause_frame = false;
02909
02910 if (xvmc_tex)
02911 {
02912 xvmc_tex->Show(scan);
02913
02914
02915 CheckFrameStates();
02916 return;
02917 }
02918
02919 vbuffers.begin_lock(kVideoBuffer_pause);
02920 if (vbuffers.size(kVideoBuffer_pause))
02921 {
02922 frame = vbuffers.head(kVideoBuffer_pause);
02923 #ifdef DEBUG_PAUSE
02924 VERBOSE(VB_PLAYBACK, LOC + QString("use pause frame: %1 ShowXvMC")
02925 .arg(DebugString(frame)));
02926 #endif // DEBUG_PAUSE
02927 using_pause_frame = true;
02928 }
02929 else if (vbuffers.size(kVideoBuffer_used))
02930 frame = vbuffers.head(kVideoBuffer_used);
02931 vbuffers.end_lock();
02932
02933 if (!frame)
02934 {
02935 VERBOSE(VB_PLAYBACK, LOC + "ShowXvMC(): No frame to show");
02936 return;
02937 }
02938
02939 vbuffers.LockFrame(frame, "ShowXvMC");
02940
02941
02942 int field = 3, src_y = video_rect.top(), dest_y = display_video_rect.top();
02943 int xv_src_y_incr = 0, xv_dest_y_incr = 0;
02944 if (m_deinterlacing)
02945 {
02946 calc_bob(scan,
02947 video_rect.height(), display_video_rect.height(),
02948 video_rect.top(), display_video_rect.top(),
02949 frame->height, frame->top_field_first,
02950 field, src_y, dest_y, xv_src_y_incr, xv_dest_y_incr);
02951 }
02952 if (hasVLDAcceleration())
02953 {
02954 src_y = video_rect.top();
02955 dest_y = display_video_rect.top();
02956 }
02957
02958
02959 VideoFrame *osdframe = vbuffers.GetOSDFrame(frame);
02960 if (osdframe && !vbuffers.TryLockFrame(osdframe, "ShowXvMC -- osd"))
02961 {
02962 VERBOSE(VB_IMPORTANT, LOC_ERR + "ShowXvMC(): Unable to get OSD lock");
02963 vbuffers.safeEnqueue(kVideoBuffer_displayed, osdframe);
02964 osdframe = NULL;
02965 }
02966
02967
02968 xvmc_render_state_t *showingsurface = (osdframe) ?
02969 GetRender(osdframe) : GetRender(frame);
02970 XvMCSurface *surf = showingsurface->p_surface;
02971
02972
02973 X11L;
02974 XvMCPutSurface(XJ_disp, surf, XJ_curwin,
02975 video_rect.left(), src_y,
02976 video_rect.width(), video_rect.height(),
02977 display_video_rect.left(), dest_y,
02978 display_video_rect.width(),
02979 display_video_rect.height(), field);
02980 XFlush(XJ_disp);
02981 X11U;
02982
02983
02984 if (!using_pause_frame)
02985 {
02986 while (vbuffers.size(kVideoBuffer_pause))
02987 DiscardFrame(vbuffers.dequeue(kVideoBuffer_pause));
02988 }
02989
02990 CheckFrameStates();
02991
02992
02993 vbuffers.UnlockFrame(osdframe, "ShowXvMC -- OSD");
02994 vbuffers.UnlockFrame(frame, "ShowXvMC");
02995
02996
02997 vbuffers.safeEnqueue(kVideoBuffer_displayed, osdframe);
02998 #endif // USING_XVMC
02999 }
03000
03001 void VideoOutputXv::ShowXVideo(FrameScanType scan)
03002 {
03003 VideoFrame *frame = GetLastShownFrame();
03004
03005 vbuffers.LockFrame(frame, "ShowXVideo");
03006
03007 XvImage *image = (XvImage*) xv_buffers[frame->buf];
03008 if (!image)
03009 {
03010 vbuffers.UnlockFrame(frame, "ShowXVideo");
03011 return;
03012 }
03013
03014 int field = 3, src_y = video_rect.top(), dest_y = display_video_rect.top(),
03015 xv_src_y_incr = 0, xv_dest_y_incr = 0;
03016 if (m_deinterlacing && (m_deintfiltername == "bobdeint"))
03017 {
03018 calc_bob(scan,
03019 video_rect.height(), display_video_rect.height(),
03020 video_rect.top(), display_video_rect.top(),
03021 frame->height, frame->top_field_first,
03022 field, src_y, dest_y, xv_src_y_incr, xv_dest_y_incr);
03023 src_y += xv_src_y_incr;
03024 dest_y += xv_dest_y_incr;
03025 }
03026
03027 vbuffers.UnlockFrame(frame, "ShowXVideo");
03028 {
03029 QMutexLocker locker(&global_lock);
03030 vbuffers.LockFrame(frame, "ShowXVideo");
03031 int video_height = (3 != field) ?
03032 (video_rect.height()/2) : video_rect.height();
03033 X11S(XvShmPutImage(XJ_disp, xv_port, XJ_curwin,
03034 XJ_gc, image,
03035 video_rect.left(), src_y,
03036 video_rect.width(), video_height,
03037 display_video_rect.left(), dest_y,
03038 display_video_rect.width(),
03039 display_video_rect.height(), False));
03040 vbuffers.UnlockFrame(frame, "ShowXVideo");
03041 }
03042 }
03043
03044
03045 void VideoOutputXv::Show(FrameScanType scan)
03046 {
03047 if (IsErrored())
03048 {
03049 VERBOSE(VB_IMPORTANT, LOC_ERR + "IsErrored() is true in Show()");
03050 return;
03051 }
03052
03053 if ((needrepaint || xv_need_bobdeint_repaint) &&
03054 (VideoOutputSubType() >= XVideo) && !embedding)
03055 {
03056 DrawUnusedRects(false);
03057 }
03058
03059 if (VideoOutputSubType() > XVideo)
03060 ShowXvMC(scan);
03061 else if (VideoOutputSubType() == XVideo)
03062 ShowXVideo(scan);
03063 else if (VideoOutputSubType() == OpenGL)
03064 {
03065 QMutexLocker locker(&gl_context_lock);
03066 gl_context->SwapBuffers();
03067 }
03068
03069 X11S(XSync(XJ_disp, False));
03070 }
03071
03072 void VideoOutputXv::ShowPip(VideoFrame *frame, NuppelVideoPlayer *pipplayer)
03073 {
03074 if (VideoOutputSubType() != OpenGL)
03075 {
03076 VideoOutput::ShowPip(frame, pipplayer);
03077 return;
03078 }
03079
03080 (void) frame;
03081
03082 gl_pip_ready = false;
03083
03084 if (!pipplayer)
03085 return;
03086
03087 int pipw, piph;
03088 VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
03089 float pipVideoAspect = pipplayer->GetVideoAspect();
03090 QSize pipVideoDim = pipplayer->GetVideoBufferSize();
03091 uint pipVideoWidth = pipVideoDim.width();
03092 uint pipVideoHeight = pipVideoDim.height();
03093
03094
03095 if ((pipVideoAspect <= 0) || !pipimage ||
03096 !pipimage->buf || pipimage->codec != FMT_YV12)
03097 {
03098 pipplayer->ReleaseCurrentFrame(pipimage);
03099 return;
03100 }
03101
03102 QRect position = GetPIPRect(db_pip_location, pipplayer);
03103
03104 if (!gl_pipchain)
03105 {
03106 VERBOSE(VB_PLAYBACK, LOC + "Initialise PiP.");
03107 gl_pipchain = new OpenGLVideo();
03108 bool success = gl_pipchain->Init(gl_context, db_use_picture_controls,
03109 true, QSize(pipVideoWidth, pipVideoHeight),
03110 position, position,
03111 QRect(0, 0, pipVideoWidth, pipVideoHeight), false);
03112 success &= gl_pipchain->AddDeinterlacer("openglonefield");
03113 gl_pipchain->SetMasterViewport(gl_videochain->GetViewPort());
03114 if (!success)
03115 {
03116 pipplayer->ReleaseCurrentFrame(pipimage);
03117 return;
03118 }
03119 }
03120
03121 QSize current = gl_pipchain->GetVideoSize();
03122 if ((uint)current.width() != pipVideoWidth ||
03123 (uint)current.height() != pipVideoHeight)
03124 {
03125 VERBOSE(VB_PLAYBACK, LOC + "Re-initialise PiP.");
03126
03127 bool success = gl_pipchain->ReInit(
03128 gl_context, db_use_picture_controls,
03129 true, QSize(pipVideoWidth, pipVideoHeight),
03130 position, position,
03131 QRect(0, 0, pipVideoWidth, pipVideoHeight), false);
03132
03133 gl_pipchain->SetMasterViewport(gl_videochain->GetViewPort());
03134 if (!success)
03135 {
03136 pipplayer->ReleaseCurrentFrame(pipimage);
03137 return;
03138 }
03139
03140 }
03141 gl_pipchain->SetVideoRect(position,
03142 QRect(0, 0, pipVideoWidth, pipVideoHeight));
03143 gl_pipchain->UpdateInputFrame(pipimage);
03144
03145 gl_pip_ready = true;
03146
03147 pipplayer->ReleaseCurrentFrame(pipimage);
03148 }
03149
03150 void VideoOutputXv::DrawUnusedRects(bool sync)
03151 {
03152 if (VideoOutputSubType() == OpenGL)
03153 return;
03154
03155
03156 bool use_bob = (m_deinterlacing && m_deintfiltername == "bobdeint");
03157 int boboff_raw = (int)round(((double)display_video_rect.height()) /
03158 456 - 0.00001);
03159 int boboff = use_bob ? boboff_raw : 0;
03160
03161 xv_need_bobdeint_repaint |= needrepaint;
03162
03163 if (chroma_osd && chroma_osd->GetImage() && xv_need_bobdeint_repaint)
03164 {
03165 X11L;
03166 XShmPutImage(XJ_disp, XJ_curwin, XJ_gc, chroma_osd->GetImage(),
03167 0, 0, 0, 0,
03168 display_visible_rect.width(),
03169 display_visible_rect.height(), False);
03170 if (sync)
03171 XSync(XJ_disp, false);
03172 X11U;
03173
03174 needrepaint = false;
03175 xv_need_bobdeint_repaint = false;
03176 return;
03177 }
03178
03179 X11L;
03180
03181
03182
03183
03184 bool clrdraw = xv_colorkey || !embedding;
03185
03186 if (xv_draw_colorkey && needrepaint && clrdraw)
03187 {
03188 XSetForeground(XJ_disp, XJ_gc, xv_colorkey);
03189 XFillRectangle(XJ_disp, XJ_curwin, XJ_gc,
03190 display_visible_rect.left(),
03191 display_visible_rect.top() + boboff,
03192 display_visible_rect.width(),
03193 display_visible_rect.height() - 2 * boboff);
03194 }
03195 else if (xv_draw_colorkey && xv_need_bobdeint_repaint && clrdraw)
03196 {
03197
03198
03199 XSetForeground(XJ_disp, XJ_gc, xv_colorkey);
03200 XFillRectangle(XJ_disp, XJ_curwin, XJ_gc,
03201 display_visible_rect.left(),
03202 display_visible_rect.top(),
03203 display_visible_rect.width(),
03204 boboff_raw);
03205 XFillRectangle(XJ_disp, XJ_curwin, XJ_gc,
03206 display_visible_rect.left(),
03207 display_visible_rect.height() - 2 * boboff_raw,
03208 display_visible_rect.width(),
03209 display_visible_rect.height());
03210 }
03211
03212 needrepaint = false;
03213 xv_need_bobdeint_repaint = false;
03214
03215
03216 XSetForeground(XJ_disp, XJ_gc, XJ_letterbox_colour);
03217
03218 if (display_video_rect.left() > display_visible_rect.left())
03219 {
03220 XFillRectangle(XJ_disp, XJ_curwin, XJ_gc,
03221 display_visible_rect.left(),
03222 display_visible_rect.top(),
03223 display_video_rect.left() - display_visible_rect.left(),
03224 display_visible_rect.height());
03225 }
03226 if (display_video_rect.left() + display_video_rect.width() <
03227 display_visible_rect.left() + display_visible_rect.width())
03228 {
03229 XFillRectangle(XJ_disp, XJ_curwin, XJ_gc,
03230 display_video_rect.left() + display_video_rect.width(),
03231 display_visible_rect.top(),
03232 (display_visible_rect.left() +
03233 display_visible_rect.width()) -
03234 (display_video_rect.left() +
03235 display_video_rect.width()),
03236 display_visible_rect.height());
03237 }
03238 if (display_video_rect.top() + boboff > display_visible_rect.top())
03239 {
03240 XFillRectangle(XJ_disp, XJ_curwin, XJ_gc,
03241 display_visible_rect.left(),
03242 display_visible_rect.top(),
03243 display_visible_rect.width(),
03244 display_video_rect.top() + boboff -
03245 display_visible_rect.top());
03246 }
03247 if (display_video_rect.top() + display_video_rect.height() <
03248 display_visible_rect.top() + display_visible_rect.height())
03249 {
03250 XFillRectangle(XJ_disp, XJ_curwin, XJ_gc,
03251 display_visible_rect.left(),
03252 display_video_rect.top() + display_video_rect.height(),
03253 display_visible_rect.width(),
03254 (display_visible_rect.top() +
03255 display_visible_rect.height()) -
03256 (display_video_rect.top() +
03257 display_video_rect.height()));
03258 }
03259
03260 if (sync)
03261 XSync(XJ_disp, false);
03262
03263 X11U;
03264 }
03265
03271 void VideoOutputXv::DrawSlice(VideoFrame *frame, int x, int y, int w, int h)
03272 {
03273 (void)frame;
03274 (void)x;
03275 (void)y;
03276 (void)w;
03277 (void)h;
03278
03279 if (VideoOutputSubType() <= XVideo)
03280 return;
03281
03282 #ifdef USING_XVMC
03283 xvmc_render_state_t *render = GetRender(frame);
03284
03285 if (render->p_past_surface == render->p_surface)
03286 render->p_past_surface = NULL;
03287 vbuffers.AddInheritence(frame);
03288
03289 Status status;
03290 if (hasVLDAcceleration())
03291 {
03292 vbuffers.LockFrame(frame, "DrawSlice -- VLD");
03293 X11S(status = XvMCPutSlice2(XJ_disp, xvmc_ctx,
03294 (char*)render->slice_data,
03295 render->slice_datalen,
03296 render->slice_code));
03297 if (Success != status)
03298 VERBOSE(VB_PLAYBACK, LOC_ERR + "XvMCPutSlice: "<<status);
03299
03300 #if 0
03301
03302 render->start_mv_blocks_num = 0;
03303 render->filled_mv_blocks_num = 0;
03304 render->next_free_data_block_num = 0;
03305 #endif
03306
03307 vbuffers.UnlockFrame(frame, "DrawSlice -- VLD");
03308 }
03309 else
03310 {
03311 vector<const VideoFrame*> locks;
03312 locks.push_back(vbuffers.PastFrame(frame));
03313 locks.push_back(vbuffers.FutureFrame(frame));
03314 locks.push_back(frame);
03315 vbuffers.LockFrames(locks, "DrawSlice");
03316
03317
03318 X11S(status =
03319 XvMCRenderSurface(XJ_disp, xvmc_ctx,
03320 render->picture_structure,
03321 render->p_surface,
03322 render->p_past_surface,
03323 render->p_future_surface,
03324 render->flags,
03325 render->filled_mv_blocks_num,
03326 render->start_mv_blocks_num,
03327 (XvMCMacroBlockArray *)frame->priv[1],
03328 (XvMCBlockArray *)frame->priv[0]));
03329
03330 if (Success != status)
03331 VERBOSE(VB_PLAYBACK, LOC_ERR +
03332 QString("XvMCRenderSurface: %1 (%2)")
03333 .arg(ErrorStringXvMC(status)).arg(status));
03334 else
03335 FlushSurface(frame);
03336
03337 render->start_mv_blocks_num = 0;
03338 render->filled_mv_blocks_num = 0;
03339 render->next_free_data_block_num = 0;
03340 vbuffers.UnlockFrames(locks, "DrawSlice");
03341 }
03342 #endif // USING_XVMC
03343 }
03344
03345
03346 void VideoOutputXv::VideoAspectRatioChanged(float aspect)
03347 {
03348 QMutexLocker locker(&global_lock);
03349 VideoOutput::VideoAspectRatioChanged(aspect);
03350 }
03351
03352
03353 void VideoOutputXv::CopyFrame(VideoFrame *to, const VideoFrame *from)
03354 {
03355 if (VideoOutputSubType() <= XVideo)
03356 VideoOutput::CopyFrame(to, from);
03357 else if (xvmc_tex)
03358 {
03359 global_lock.lock();
03360 int tmp = framesPlayed;
03361 global_lock.unlock();
03362
03363 PrepareFrameXvMC((VideoFrame*)from, kScan_Interlaced);
03364
03365 global_lock.lock();
03366 framesPlayed = tmp;
03367 global_lock.unlock();
03368 }
03369 }
03370
03371 void VideoOutputXv::UpdatePauseFrame(void)
03372 {
03373 QMutexLocker locker(&global_lock);
03374
03375 VERBOSE(VB_PLAYBACK, LOC + "UpdatePauseFrame() " + vbuffers.GetStatus());
03376
03377 if ((VideoOutputSubType() <= XVideo) ||
03378 (VideoOutputSubType() == OpenGL) || xvmc_tex)
03379 {
03380
03381 vbuffers.LockFrame(&av_pause_frame, "UpdatePauseFrame -- pause");
03382
03383 vbuffers.begin_lock(kVideoBuffer_used);
03384 VideoFrame *used_frame = NULL;
03385 if (vbuffers.size(kVideoBuffer_used) > 0)
03386 {
03387 used_frame = vbuffers.head(kVideoBuffer_used);
03388 if (!vbuffers.TryLockFrame(used_frame, "UpdatePauseFrame -- used"))
03389 used_frame = NULL;
03390 }
03391 if (used_frame)
03392 {
03393 CopyFrame(&av_pause_frame, used_frame);
03394 vbuffers.UnlockFrame(used_frame, "UpdatePauseFrame -- used");
03395 }
03396 vbuffers.end_lock();
03397
03398 if (!used_frame && !xvmc_tex &&
03399 vbuffers.TryLockFrame(vbuffers.GetScratchFrame(),
03400 "UpdatePauseFrame -- scratch"))
03401 {
03402 vbuffers.GetScratchFrame()->frameNumber = framesPlayed - 1;
03403 CopyFrame(&av_pause_frame, vbuffers.GetScratchFrame());
03404 vbuffers.UnlockFrame(vbuffers.GetScratchFrame(),
03405 "UpdatePauseFrame -- scratch");
03406 }
03407 vbuffers.UnlockFrame(&av_pause_frame, "UpdatePauseFrame - used");
03408 }
03409 #ifdef USING_XVMC
03410 else
03411 {
03412 if (vbuffers.size(kVideoBuffer_pause)>1)
03413 {
03414 VERBOSE(VB_PLAYBACK, LOC_ERR + "UpdatePauseFrame(): "
03415 "Pause buffer size>1 check, " + QString("size = %1")
03416 .arg(vbuffers.size(kVideoBuffer_pause)));
03417 while (vbuffers.size(kVideoBuffer_pause))
03418 DiscardFrame(vbuffers.dequeue(kVideoBuffer_pause));
03419 CheckFrameStates();
03420 } else if (1 == vbuffers.size(kVideoBuffer_pause))
03421 {
03422 VideoFrame *frame = vbuffers.dequeue(kVideoBuffer_used);
03423 if (frame)
03424 {
03425 while (vbuffers.size(kVideoBuffer_pause))
03426 DiscardFrame(vbuffers.dequeue(kVideoBuffer_pause));
03427 vbuffers.safeEnqueue(kVideoBuffer_pause, frame);
03428 VERBOSE(VB_PLAYBACK, LOC + "UpdatePauseFrame(): "
03429 "XvMC using NEW pause frame");
03430 }
03431 else
03432 VERBOSE(VB_PLAYBACK, LOC + "UpdatePauseFrame(): "
03433 "XvMC using OLD pause frame");
03434 return;
03435 }
03436
03437 frame_queue_t::iterator it =
03438 vbuffers.begin_lock(kVideoBuffer_displayed);
03439
03440 VERBOSE(VB_PLAYBACK, LOC + "UpdatePauseFrame -- XvMC");
03441 if (vbuffers.size(kVideoBuffer_displayed))
03442 {
03443 VERBOSE(VB_PLAYBACK, LOC + "UpdatePauseFrame -- XvMC: "
03444 "\n\t\t\tFound a pause frame in display");
03445
03446 VideoFrame *frame = vbuffers.tail(kVideoBuffer_displayed);
03447 if (vbuffers.GetOSDParent(frame))
03448 frame = vbuffers.GetOSDParent(frame);
03449 vbuffers.safeEnqueue(kVideoBuffer_pause, frame);
03450 }
03451 vbuffers.end_lock();
03452
03453 if (1 != vbuffers.size(kVideoBuffer_pause))
03454 {
03455 VERBOSE(VB_PLAYBACK, LOC + "UpdatePauseFrame -- XvMC: "
03456 "\n\t\t\tDid NOT find a pause frame");
03457 }
03458 }
03459 #endif
03460 }
03461
03462 void VideoOutputXv::ProcessFrameXvMC(VideoFrame *frame, OSD *osd)
03463 {
03464 (void)frame;
03465 (void)osd;
03466 #ifdef USING_XVMC
03467 if (xvmc_tex)
03468 {
03469 xvmc_tex->ProcessOSD(osd);
03470 return;
03471 }
03472
03473
03474 if (frame)
03475 {
03476 vbuffers.LockFrame(frame, "ProcessFrameXvMC");
03477 while (vbuffers.size(kVideoBuffer_pause))
03478 DiscardFrame(vbuffers.dequeue(kVideoBuffer_pause));
03479 }
03480 else
03481 {
03482 bool success = false;
03483
03484 frame_queue_t::iterator it = vbuffers.begin_lock(kVideoBuffer_pause);
03485 if (vbuffers.size(kVideoBuffer_pause))
03486 {
03487 frame = vbuffers.head(kVideoBuffer_pause);
03488 success = vbuffers.TryLockFrame(
03489 frame, "ProcessFrameXvMC -- reuse");
03490 }
03491 vbuffers.end_lock();
03492
03493 if (success)
03494 {
03495 #ifdef DEBUG_PAUSE
03496 VERBOSE(VB_PLAYBACK, LOC + "ProcessFrameXvMC: " +
03497 QString("Use pause frame: %1").arg(DebugString(frame)));
03498 #endif // DEBUG_PAUSE
03499 vbuffers.SetOSDFrame(frame, NULL);
03500 }
03501 else
03502 {
03503 VERBOSE(VB_IMPORTANT, LOC + "ProcessFrameXvMC: "
03504 "Tried to reuse frame but failed");
03505 frame = NULL;
03506 }
03507 }
03508
03509
03510 if (chroma_osd)
03511 {
03512 vbuffers.UnlockFrame(frame, "ProcessFrameXvMC");
03513 QMutexLocker locker(&global_lock);
03514 if (!embedding && osd)
03515 needrepaint |= chroma_osd->ProcessOSD(osd);
03516 return;
03517 }
03518
03520
03521 if (!frame)
03522 {
03523 VERBOSE(VB_IMPORTANT, LOC + "ProcessFrameXvMC: "
03524 "Called without frame");
03525 return;
03526 }
03527
03528 if (!xvmc_buf_attr->GetOSDNum())
03529 {
03530 vbuffers.UnlockFrame(frame, "ProcessFrameXvMC");
03531 return;
03532 }
03533
03534 VideoFrame * old_osdframe = vbuffers.GetOSDFrame(frame);
03535 if (old_osdframe)
03536 {
03537 VERBOSE(VB_IMPORTANT, LOC + "ProcessFrameXvMC:\n\t\t\t" +
03538 QString("Warning, %1 is still marked as the OSD frame of %2.")
03539 .arg(DebugString(old_osdframe, true))
03540 .arg(DebugString(frame, true)));
03541
03542 vbuffers.SetOSDFrame(frame, NULL);
03543 }
03544
03545 XvMCOSD* xvmc_osd = NULL;
03546 if (!embedding && osd)
03547 xvmc_osd = GetAvailableOSD();
03548
03549 if (xvmc_osd && xvmc_osd->IsValid())
03550 {
03551 VideoFrame *osdframe = NULL;
03552 int ret = DisplayOSD(xvmc_osd->OSDFrame(), osd, -1,
03553 xvmc_osd->GetRevision());
03554 OSDSurface *osdsurf = osd->GetDisplaySurface();
03555 if (osdsurf)
03556 xvmc_osd->SetRevision(osdsurf->GetRevision());
03557 if (ret >= 0 && xvmc_osd->NeedFrame())
03558 {
03559
03560
03561 if (!vbuffers.size(kVideoBuffer_avail))
03562 CheckFrameStates();
03563
03564
03565
03566 if (!vbuffers.size(kVideoBuffer_avail))
03567 {
03568 frame_queue_t::iterator it;
03569 it = vbuffers.begin_lock(kVideoBuffer_displayed);
03570 for (;it != vbuffers.end(kVideoBuffer_displayed); ++it)
03571 if (*it != frame)
03572 X11S(XvMCHideSurface(XJ_disp,
03573 GetRender(*it)->p_surface));
03574 vbuffers.end_lock();
03575
03576 CheckFrameStates();
03577 }
03578
03579
03580 if (vbuffers.size(kVideoBuffer_avail))
03581 {
03582 osdframe = vbuffers.GetNextFreeFrame(false, false);
03583
03584 if (frame == osdframe)
03585 {
03586 VERBOSE(VB_IMPORTANT, LOC_ERR +
03587 QString("ProcessFrameXvMC: %1 %2")
03588 .arg(DebugString(frame, true))
03589 .arg(vbuffers.GetStatus()));
03590 osdframe = NULL;
03591 }
03592 }
03593
03594 if (osdframe && vbuffers.TryLockFrame(
03595 osdframe, "ProcessFrameXvMC -- OSD"))
03596 {
03597 vbuffers.SetOSDFrame(osdframe, NULL);
03598 xvmc_osd->CompositeOSD(frame, osdframe);
03599 vbuffers.UnlockFrame(osdframe, "ProcessFrameXvMC -- OSD");
03600 vbuffers.SetOSDFrame(frame, osdframe);
03601 }
03602 else
03603 {
03604 VERBOSE(VB_IMPORTANT, LOC_ERR + "ProcessFrameXvMC: "
03605 "Failed to get OSD lock");
03606 DiscardFrame(osdframe);
03607 }
03608 }
03609 if (ret >= 0 && !xvmc_osd->NeedFrame())
03610 {
03611 xvmc_osd->CompositeOSD(frame);
03612 }
03613 }
03614 if (xvmc_osd)
03615 ReturnAvailableOSD(xvmc_osd);
03616 vbuffers.UnlockFrame(frame, "ProcessFrameXvMC");
03617 #endif // USING_XVMC
03618 }
03619
03620 #ifdef USING_XVMC
03621 XvMCOSD* VideoOutputXv::GetAvailableOSD()
03622 {
03623 if (xvmc_buf_attr->GetOSDNum() > 1)
03624 {
03625 XvMCOSD *val = NULL;
03626 xvmc_osd_lock.lock();
03627 while (!xvmc_osd_available.size())
03628 {
03629 xvmc_osd_lock.unlock();
03630 usleep(50);
03631 xvmc_osd_lock.lock();
03632 }
03633 val = xvmc_osd_available.dequeue();
03634 xvmc_osd_lock.unlock();
03635 return val;
03636 }
03637 else if (xvmc_buf_attr->GetOSDNum() > 0)
03638 {
03639 xvmc_osd_lock.lock();
03640 return xvmc_osd_available.head();
03641 }
03642 return NULL;
03643 }
03644 #endif // USING_XVMC
03645
03646 #ifdef USING_XVMC
03647 void VideoOutputXv::ReturnAvailableOSD(XvMCOSD *avail)
03648 {
03649 if (xvmc_buf_attr->GetOSDNum() > 1)
03650 {
03651 xvmc_osd_lock.lock();
03652 xvmc_osd_available.push_front(avail);
03653 xvmc_osd_lock.unlock();
03654 }
03655 else if (xvmc_buf_attr->GetOSDNum() > 0)
03656 {
03657 xvmc_osd_lock.unlock();
03658 }
03659 }
03660 #endif // USING_XVMC
03661
03662 void VideoOutputXv::ProcessFrameOpenGL(VideoFrame *frame, OSD *osd,
03663 FilterChain *filterList,
03664 NuppelVideoPlayer *pipPlayer)
03665 {
03666 (void) osd;
03667 (void) filterList;
03668 (void) pipPlayer;
03669
03670 QMutexLocker locker(&gl_context_lock);
03671
03672 bool pauseframe = false;
03673 if (!frame)
03674 {
03675 frame = vbuffers.GetScratchFrame();
03676 CopyFrame(vbuffers.GetScratchFrame(), &av_pause_frame);
03677 pauseframe = true;
03678 }
03679
03680
03681 gl_context->MakeCurrent(true);
03682
03683 if (filterList)
03684 filterList->ProcessFrame(frame);
03685
03686 bool safepauseframe = pauseframe && !IsBobDeint();
03687 if (m_deinterlacing && m_deintFilter != NULL &&
03688 m_deinterlaceBeforeOSD && (!pauseframe || safepauseframe))
03689 {
03690 m_deintFilter->ProcessFrame(frame);
03691 }
03692
03693 ShowPip(frame, pipPlayer);
03694
03695 DisplayOSD(frame, osd);
03696
03697 if (m_deinterlacing && m_deintFilter != NULL &&
03698 !m_deinterlaceBeforeOSD && (!pauseframe || safepauseframe))
03699 {
03700 m_deintFilter->ProcessFrame(frame);
03701 }
03702
03703 if (gl_videochain)
03704 gl_videochain->UpdateInputFrame(frame);
03705
03706 gl_context->MakeCurrent(false);
03707 }
03708
03709 void VideoOutputXv::ProcessFrameMem(VideoFrame *frame, OSD *osd,
03710 FilterChain *filterList,
03711 NuppelVideoPlayer *pipPlayer)
03712 {
03713 bool deint_proc = m_deinterlacing && (m_deintFilter != NULL);
03714 bool pauseframe = false;
03715 if (!frame)
03716 {
03717 frame = vbuffers.GetScratchFrame();
03718 vector<const VideoFrame*> locks;
03719 locks.push_back(frame);
03720 locks.push_back(&av_pause_frame);
03721 vbuffers.LockFrames(locks, "ProcessFrameMem -- pause");
03722 CopyFrame(frame, &av_pause_frame);
03723 vbuffers.UnlockFrames(locks, "ProcessFrameMem -- pause");
03724 pauseframe = true;
03725 }
03726
03727 vbuffers.LockFrame(frame, "ProcessFrameMem");
03728
03729 bool safepauseframe = pauseframe && !IsBobDeint();
03730 if (!pauseframe || safepauseframe)
03731 {
03732 if (filterList)
03733 filterList->ProcessFrame(frame);
03734
03735 if (deint_proc && m_deinterlaceBeforeOSD)
03736 m_deintFilter->ProcessFrame(frame);
03737 }
03738
03739 ShowPip(frame, pipPlayer);
03740
03741 if (osd && !embedding)
03742 {
03743 if (!chroma_osd)
03744 DisplayOSD(frame, osd);
03745 else
03746 {
03747 QMutexLocker locker(&global_lock);
03748 needrepaint |= chroma_osd->ProcessOSD(osd);
03749 }
03750 }
03751
03752 if ((!pauseframe || safepauseframe) &&
03753 deint_proc && !m_deinterlaceBeforeOSD)
03754 {
03755 m_deintFilter->ProcessFrame(frame);
03756 }
03757
03758 vbuffers.UnlockFrame(frame, "ProcessFrameMem");
03759 }
03760
03761
03762 void VideoOutputXv::ProcessFrame(VideoFrame *frame, OSD *osd,
03763 FilterChain *filterList,
03764 NuppelVideoPlayer *pipPlayer)
03765 {
03766 if (IsErrored())
03767 {
03768 VERBOSE(VB_IMPORTANT, LOC_ERR + "IsErrored() in ProcessFrame()");
03769 return;
03770 }
03771
03772 if (VideoOutputSubType() == OpenGL)
03773 ProcessFrameOpenGL(frame, osd, filterList, pipPlayer);
03774 else if (VideoOutputSubType() <= XVideo)
03775 ProcessFrameMem(frame, osd, filterList, pipPlayer);
03776 else
03777 ProcessFrameXvMC(frame, osd);
03778 }
03779
03780
03781 int VideoOutputXv::SetPictureAttribute(
03782 PictureAttribute attribute, int newValue)
03783 {
03784 if (!supported_attributes)
03785 return -1;
03786
03787 if (VideoOutputSubType() == OpenGL)
03788 {
03789 newValue = min(max(newValue, 0), 100);
03790 newValue = gl_videochain->SetPictureAttribute(attribute, newValue);
03791 if (newValue >= 0)
03792 SetPictureAttributeDBValue(attribute, newValue);
03793 return newValue;
03794 }
03795
03796 QString attrName = toXVString(attribute);
03797 int valAdj = (kPictureAttribute_Hue == attribute) ? xv_hue_base : 0;
03798
03799 if (attrName.isEmpty())
03800 {
03801 VERBOSE(VB_IMPORTANT, "\n\n\n attrName.isEmpty() \n\n\n");
03802 return -1;
03803 }
03804
03805 if (0 == (toMask(attribute) & supported_attributes))
03806 {
03807 VERBOSE(VB_IMPORTANT, "\n\n\n unsupported attribute \n\n\n");
03808 return -1;
03809 }
03810
03811 newValue = min(max(newValue, 0), 100);
03812 if (kPictureAttribute_Hue == attribute)
03813 {
03814 int oldValue = GetPictureAttribute(attribute);
03815 newValue = (0 == newValue && oldValue > 0 && oldValue < 5) ?
03816 100 : ((100 == newValue && oldValue > 95 && oldValue < 100) ?
03817 0 : newValue);
03818 }
03819
03820 int port_min = xv_attribute_min[attribute];
03821 int port_max = xv_attribute_max[attribute];
03822 int range = port_max - port_min;
03823
03824 int tmpval2 = (newValue + valAdj) % 100;
03825 int tmpval3 = (int) roundf(range * 0.01f * tmpval2);
03826 int value = min(tmpval3 + port_min, port_max);
03827
03828 xv_set_attrib(XJ_disp, xv_port, attrName.ascii(), value);
03829
03830 #ifdef USING_XVMC
03831
03832 if (