• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files

videoout_xv.cpp

Go to the documentation of this file.
00001 #include "NuppelVideoPlayer.h"
00002 
00003 /* Based on xqcam.c by Paul Chinn <loomer@svpal.org> */
00004 
00005 // ANSI C headers
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 // MythTV OSD headers
00027 #include "yuv2rgb.h"
00028 #include "osd.h"
00029 #include "osdsurface.h"
00030 #include "osdxvmc.h"
00031 #include "osdchromakey.h"
00032 
00033 // MythTV X11 headers
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 // MythTV General headers
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 // MythTV OpenGL headers
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     // If using custom display resolutions, display_res will point
00138     // to a singleton instance of the DisplayRes class
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     // Delete the video buffers
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     // ungrab port...
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     // Switch back to desired resolution for GUI
00195     if (display_res)
00196         display_res->SwitchToGUI();
00197 }
00198 
00199 // this is documented in videooutbase.cpp
00200 void VideoOutputXv::Zoom(ZoomDirection direction)
00201 {
00202     QMutexLocker locker(&global_lock);
00203     VideoOutput::Zoom(direction);
00204     MoveResize();
00205 }
00206 
00207 // this is documented in videooutbase.cpp
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 // documented in videooutbase.cpp
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         // ungrab port...
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 // documented in videooutbase.cpp
00298 QRect VideoOutputXv::GetVisibleOSDBounds(
00299     float &visible_aspect, float &font_scaling, float themeaspect) const
00300 {
00301     // This rounding works for I420 video...
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 // documented in videooutbase.cpp
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     // Catch bad data from video drivers (divide by zero causes return of NaN)
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     // Assume 60Hz if rate isn't good:
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; // ATSC 1920x1080
00407 
00408     if (display_res && display_res->SwitchToVideo(width, height))
00409     {
00410         // Switching to custom display resolution succeeded
00411         // Make a note of the new size
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         // if width && height are zero users expect fullscreen playback
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             // Resize X window to fill new resolution
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         // The very first Resize needs to be the maximum possible
00451         // desired res, because X will mask off anything outside
00452         // the initial dimensions
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         // Get default (possibly user selected) screen resolution from context
00466         float wmult, hmult;
00467         gContext->GetScreenSettings(XJ_screenx, XJ_screenwidth, wmult,
00468                                     XJ_screeny, XJ_screenheight, hmult);
00469     }
00470 
00471     // Fetch pixel width and height of the display
00472     int xbase, ybase, w, h;
00473     gContext->GetScreenBounds(xbase, ybase, w, h);
00474 
00475     // Determine window dimensions in pixels
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     // Determine if we are using Xinerama
00490     bool usingXinerama = (GetNumberOfXineramaScreens() > 1);
00491 
00492     // If the dimensions are invalid, assume square pixels and 17" screen.
00493     // Only print warning if this isn't Xinerama, we will fix Xinerama later.
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     // If we are using Xinerama the display dimensions can not be trusted.
00504     // We need to use the Xinerama monitor aspect ratio from the DB to set
00505     // the physical screen width. This assumes the height is correct, which
00506     // is more or less true in the typical side-by-side monitor setup.
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     // We must now scale the display measurements to our window size.
00524     // If we are running fullscreen this is a no-op.
00525     display_dim = QSize((display_dim.width()  * window_w) / w,
00526                         (display_dim.height() * window_h) / h);
00527 
00528     // Now that we know the physical monitor size, we can
00529     // calculate the display aspect ratio pretty simply...
00530     display_aspect = ((float)display_dim.width()) / display_dim.height();
00531 
00532     // If we are using XRandR, use the aspect ratio from it instead...
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     // avoid compiler warnings
00576     (void)xvmc_chroma; (void)xvmc_surf_info;
00577 
00578     if (adaptor_name)
00579         *adaptor_name = QString::null;
00580 
00581     // figure out what basic kind of surface we want..
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     // create list of requirements to check in order..
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     // try to get an adapter with picture attributes
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     // figure out if we want chromakeying..
00652     VideoDisplayProfile vdp;
00653     vdp.SetInput(QSize(width, height));
00654     bool check_for_colorkey = (vdp.GetOSDRenderer() == "chromakey");
00655 
00656     // if we want colorkey capability try to get an adapter with them
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     // get the list of Xv ports
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     // find an Xv port
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     // free list of Xv ports
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     // All methods but XvMC use a pause frame, create it if needed
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     // If use_xvmc try to create XvMC buffers
00863 #ifdef USING_XVMC
00864     if (mcodecid > kCodec_NORMAL_END)
00865     {
00866         // Create ffmpeg VideoFrames
00867         bool vld, idct, mc;
00868         myth2av_codecid(myth_codec_id, vld, idct, mc);
00869 
00870         vbuffers.Init(xvmc_buf_attr->GetNumSurf(),
00871                       false /* create an extra frame for pause? */,
00872                       xvmc_buf_attr->GetFrameReserve(),
00873                       xvmc_buf_attr->GetPreBufferGoal(),
00874                       xvmc_buf_attr->GetPreBufferGoal(),
00875                       xvmc_buf_attr->GetNeededBeforeDisplay(),
00876                       true /*use_frame_locking*/);
00877 
00878 
00879         done = InitXvMC(mcodecid);
00880 
00881         if (!done)
00882             vbuffers.Reset();
00883     }
00884 #endif // USING_XVMC
00885 
00886     // Create ffmpeg VideoFrames
00887     if (!done)
00888         vbuffers.Init(31, true, 1, 12, 4, 2, false);
00889 
00890     if (!done && use_opengl)
00891         done = InitOpenGL();
00892 
00893     // Fall back to XVideo if there is an xv_port
00894     if (!done && use_xv)
00895         done = InitXVideo();
00896 
00897     // Fall back to shared memory, if we are allowed to use it
00898     if (!done && use_shm)
00899         done = InitXShm();
00900 
00901     // Fall back to plain old X calls
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             // ensure deinterlacing is re-enabled after input change
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     // create XvMC buffers
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     // IYUV is bit identical to I420, just pretend we saw I420
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     // Disable features based on environment and DB values.
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     // Disable features based on hardware capabilities.
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); // also ok if we already opened port..
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); // disable XvMC blending OSD
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         // TODO Make sure that we are using chroma-keying
01421         //      before allowing chromakey OSD rendering.
01422 
01423         // create chroma key osd structure if needed
01424         if ((32 == XJ_depth) || (24 == XJ_depth))
01425         {
01426             chroma_osd = new ChromaKeyOSD(this);
01427             xvmc_buf_attr->SetOSDNum(0); // disable XvMC blending OSD
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     // Other OSD's don't require initialization here...
01440     return true;
01441 }
01442 
01443 bool VideoOutputXv::CheckOSDInit(void)
01444 {
01445     // Deal with the nVidia 6xxx & 7xxx cards which do
01446     // not support chromakeying with the latest drivers
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     // Get rid of the chromakey osd..
01455     delete chroma_osd;
01456     chroma_osd = NULL;
01457 
01458     if (VideoOutputSubType() >= XVideoMC)
01459     {
01460         // Delete the buffers we allocated before
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     // Figure out what video renderer to use
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     // Create video buffers
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     // Initialize the OSD, if we need to
01550     InitOSD(osdrenderer);
01551 
01552     // Initialize chromakeying, if we need to
01553     if (!xvmc_tex && video_output_subtype >= XVideo)
01554         InitColorKey(true);
01555 
01556     // Check if we can actually use the OSD we want to use...
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     // Initialize the picture controls if we need to..
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     // Initialize X stuff
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     // The letterbox color..
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     // Basic setup
01610     VideoOutput::Init(width, height, aspect,
01611                       winid, winx, winy, winw, winh,
01612                       embedid);
01613 
01614     // Set resolution/measurements (check XRandR, Xinerama, config settings)
01615     InitDisplayMeasurements(width, height);
01616 
01617     // Set embedding window id
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     // handle autopaint.. Normally we try to disable it so that bob-deint 
01644     // doesn't actually bob up the top and bottom borders up and down...
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     // Check that we have a colorkey attribute and make sure it is not
01674     // the same color as the MythTV letterboxing (currently Black).
01675     // This avoids avoid bob-deint actually bobbing the borders of
01676     // the video up and down..
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         // set to MythTV letterbox color as a sentinel
01682         xv_colorkey = letterbox_color;
01683     }
01684     else if (xv_colorkey == letterbox_color)
01685     {
01686         // if it is a valid attribute and set to the letterbox color, change it
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 // documented in videooutbase.cpp
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             // make sure opengl deinterlacing is disabled
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     // clear any non opengl filters
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     // TODO implement bobdeint for non-Xv[MC]
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     // need the equivalent of 5 extra surfaces for VLD decoding -- Tegue
01959     if (surface_has_vld)
01960         num += 5;
01961 
01962     // create needed XvMC stuff
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     // For VLD decoding: the last 5 surface were allocated just to make 
02008     // sure we had enough space.  now, deallocate/destroy them. -- Tegue
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); // needed for FreeBSD?
02146                 X11U;
02147 
02148                 // Mark for delete immediately.
02149                 // It won't actually be removed until after we detach it.
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, /*offset*/0, /*data*/0,
02207                                            display_visible_rect.width(),
02208                                            display_visible_rect.height(),
02209                                            /*bitmap_pad*/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         {   // only allow these three output formats for non-xv videout
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     // XvMC buffers
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     // OSD buffers
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     // OpenGL stuff
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     // end OpenGL stuff
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 /*allow_unsafe*/)
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         // Check display status
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     // Print some debugging
02508     vbuffers.begin_lock(kVideoBuffer_displayed); // Lock X
02509     VERBOSE(VB_PLAYBACK, LOC + QString("DiscardFrames() 1: %1")
02510             .arg(vbuffers.GetStatus()));
02511     vbuffers.end_lock(); // Lock X
02512 
02513     // Finish rendering all these surfaces and move them
02514     // from the used queue to the displayed queue.
02515     // This allows us to reuse these surfaces, if they
02516     // get moved to the used list in CheckFrameStates().
02517     // This will only happen if avlib isn't using them
02518     // either and they are not currently being displayed.
02519     vbuffers.begin_lock(kVideoBuffer_displayed); // Lock Y
02520     DQ_COPY(syncs, kVideoBuffer_used);
02521     for (it = syncs.begin(); it != syncs.end(); ++it)
02522     {
02523         SyncSurface(*it, -1); // sync past
02524         SyncSurface(*it, +1); // sync future
02525         SyncSurface(*it,  0); // sync current
02526         vbuffers.safeEnqueue(kVideoBuffer_displayed, *it);
02527     }
02528     syncs.clear();
02529     vbuffers.end_lock(); // Lock Y
02530 
02531     CheckFrameStates();
02532 
02533     // If the next frame is a keyframe we can clear out a lot more...
02534     if (next_frame_keyframe)
02535     {
02536         vbuffers.begin_lock(kVideoBuffer_displayed); // Lock Z
02537 
02538         // Move all the limbo and pause frames to displayed
02539         DQ_COPY(syncs, kVideoBuffer_limbo);
02540         for (it = syncs.begin(); it != syncs.end(); ++it)
02541         {
02542             SyncSurface(*it, -1); // sync past
02543             SyncSurface(*it, +1); // sync future
02544             SyncSurface(*it,  0); // sync current
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(); // Lock Z
02552 
02553         // Now call CheckFrameStates() to remove inheritence and
02554         // move the surfaces to the used list if possible (i.e.
02555         // if avlib is not using them and they are not currently
02556         // being displayed on screen).
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     // TODO should cope with YUV422P, rgb24, argb32 etc
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 /*scan*/)
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     // bad way to throttle frame display for non-Xv mode.
02720     // calculate fps we can do and skip enough frames so we don't exceed.
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 // this is documented in videooutbase.cpp
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     // a negative offset y gives us bobbing, so adjust...
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     // nVidia v 66.29, does proper compensation when imgh==frame_height
02869     // but we need to compensate when the difference is >= 5%
02870     int mod = 0;
02871     if (frame_height>=(int)(imgh+(0.05*frame_height)) && 2==field)
02872     {
02873         //int nrml = (int) round((((double)disphoff)/frame_height) - 0.00001);
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     // DEBUG
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         // clear any displayed frames not on screen
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     // calculate bobbing params
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     {   // don't do bob-adjustment for VLD drivers
02954         src_y  = video_rect.top();
02955         dest_y = display_video_rect.top();
02956     }
02957 
02958     // get and try to lock OSD frame, if it exists
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     // set showing surface, depending on existance of osd
02968     xvmc_render_state_t *showingsurface = (osdframe) ?
02969         GetRender(osdframe) : GetRender(frame);
02970     XvMCSurface *surf = showingsurface->p_surface;
02971 
02972     // actually display the frame
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); // send XvMCPutSurface call to X11 server
02981     X11U;
02982 
02983     // if not using_pause_frame, clear old process buffer
02984     if (!using_pause_frame)
02985     {
02986         while (vbuffers.size(kVideoBuffer_pause))
02987             DiscardFrame(vbuffers.dequeue(kVideoBuffer_pause));
02988     }
02989     // clear any displayed frames not on screen
02990     CheckFrameStates();
02991 
02992     // unlock the frame[s]
02993     vbuffers.UnlockFrame(osdframe, "ShowXvMC -- OSD");
02994     vbuffers.UnlockFrame(frame, "ShowXvMC");
02995 
02996     // make sure osdframe is eventually added to available
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 // this is documented in videooutbase.cpp
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(/* don't do a sync*/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     // If PiP is not initialized to values we like, silently ignore the frame.
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     // boboff assumes the smallest interlaced resolution is 480 lines - 5%
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     // This is used to avoid drawing the colorkey when embedding and
03182     // not using overlay. This is needed because we don't paint this
03183     // in the vertical retrace period when calling this from the EPG.
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         // if this is only for deinterlacing mode switching, draw
03198         // the border areas, presumably the main image is undamaged.
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     // Set colour for masked areas
03216     XSetForeground(XJ_disp, XJ_gc, XJ_letterbox_colour); 
03217 
03218     if (display_video_rect.left() > display_visible_rect.left())
03219     { // left
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     { // right
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     { // top of screen
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     { // bottom of screen
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     // disable questionable ffmpeg surface munging
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         // TODO are these three lines really needed???
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         // Sync past & future I and P frames
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 // documented in videooutbase.cpp
03346 void VideoOutputXv::VideoAspectRatioChanged(float aspect)
03347 {
03348     QMutexLocker locker(&global_lock);
03349     VideoOutput::VideoAspectRatioChanged(aspect);
03350 }
03351 
03352 // documented in videooutbase.cpp
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         // Try used frame first, then fall back to scratch frame.
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     // Handle Pause frame
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     // Handle ChromaKey OSD
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     // Everything below this line is to support XvMC composite surface
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             // If there are no available buffer, try to toss old
03560             // displayed frames.
03561             if (!vbuffers.size(kVideoBuffer_avail))
03562                 CheckFrameStates();
03563 
03564             // If tossing doesn't work try hiding showing frames,
03565             // then tossing displayed frames.
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             // If there is an available buffer grab it.
03580             if (vbuffers.size(kVideoBuffer_avail))
03581             {
03582                 osdframe = vbuffers.GetNextFreeFrame(false, false);
03583                 // Check for error condition..
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     // disable image processing for offscreen rendering
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 // this is documented in videooutbase.cpp
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 // this is documented in videooutbase.cpp
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     // Needed for VIA XvMC to commit change immediately.
03832     if (