00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 const int kNumBuffers = 31;
00032 const int kNeedFreeFrames = 1;
00033 const int kPrebufferFramesNormal = 12;
00034 const int kPrebufferFramesSmall = 4;
00035 const int kKeepPrebuffer = 2;
00036
00037
00038
00039 #include <map>
00040 #include <vector>
00041 #include <iostream>
00042 #include <algorithm>
00043 using namespace std;
00044
00045 #include "DisplayRes.h"
00046 #include "yuv2rgb.h"
00047 #include "mythcorecontext.h"
00048 #include "filtermanager.h"
00049 #define AVCODEC_AVCODEC_H // prevent clash with QuickTime CodecType
00050 #include "videoout_quartz.h"
00051
00052 #include "util-osx.h"
00053
00054 #ifdef USING_QUARTZ_VIDEO
00055 #import <QuartzCore/CoreVideo.h>
00056 #else
00057 #import <CoreGraphics/CGBase.h>
00058 #import <CoreGraphics/CGDisplayConfiguration.h>
00059 #import <CoreGraphics/CGImage.h>
00060 #endif
00061 #import <Carbon/Carbon.h>
00062 #import <QuickTime/QuickTime.h>
00063
00064 #include "osd.h"
00065 #include "mythconfig.h"
00066 #include "mythlogging.h"
00067 #include "videodisplayprofile.h"
00068
00069 #define LOC QString("VideoOutputQuartz::")
00070
00077 class VideoOutputQuartzView
00078 {
00079 public:
00080 VideoOutputQuartzView(QuartzData *pData);
00081 virtual ~VideoOutputQuartzView();
00082
00083 virtual bool Init(void);
00084
00085 virtual void SetFrameSkip(int numskip);
00086 virtual void Show(void);
00087
00088 virtual void InputChanged(int width, int height, float aspect,
00089 MythCodecID av_codec_id);
00090 virtual void MoveResize(QRect newRect);
00091
00092 virtual void HideForGUI(void);
00093 virtual void ShowAfterGUI(QRect size);
00094
00095 protected:
00096 virtual bool Begin(void);
00097 virtual void End(void);
00098 virtual void Transform(QRect newRect);
00099 virtual void BlankScreen(bool deferred);
00100
00101
00102 virtual bool BeginPort(void) = 0;
00103 virtual void EndPort(void) = 0;
00104
00105 char * name;
00106
00107 QuartzData * parentData;
00108
00109 CGrafPtr thePort;
00110 QRect m_desired;
00111 ImageSequence theCodec;
00112 RgnHandle theMask;
00113
00114 int frameSkip;
00115 int frameCounter;
00116 bool drawBlank;
00117
00121 bool applyMoveResize;
00122
00123 QMutex viewLock;
00124 };
00125
00126
00127
00128
00129
00130 OSStatus VoqvFloater_Callback(EventHandlerCallRef inHandlerCallRef,
00131 EventRef inEvent,
00132 void *inUserData);
00133
00134
00135
00136
00137 class QuartzData
00138 {
00139 public:
00140 QuartzData() :
00141 srcWidth(0), srcHeight(0),
00142 srcAspect(1.3333f), srcMode(kAspect_Off),
00143
00144 pixelData(0), pixelSize(0),
00145 pixelLock(),
00146
00147 window(0),
00148 screen(0), refreshRate(60.0f),
00149
00150 drawInWindow(false), windowedMode(false),
00151 scaleUpVideo(false), correctGamma(false),
00152 convertI420to2VUY(NULL),
00153
00154 embeddedView(NULL)
00155 {;}
00156 ~QuartzData() { ClearViews(); }
00157
00158 void ClearViews(void)
00159 {
00160 vector<VideoOutputQuartzView*>::iterator it = views.begin();
00161 for (; it != views.end(); ++it)
00162 delete *it;
00163 views.clear();
00164 }
00165
00166
00167 int srcWidth,
00168 srcHeight;
00169 float srcAspect;
00170 int srcMode;
00171
00172
00173 ImageDescriptionHandle imgDesc;
00174 char * pixelData;
00175 size_t pixelSize;
00176 QMutex pixelLock;
00177
00178
00179 WindowRef window;
00180 Rect windowBounds;
00181 CGDirectDisplayID screen;
00182 float refreshRate;
00183
00184
00185 bool drawInWindow;
00186 bool windowedMode;
00187 bool scaleUpVideo;
00188 bool correctGamma;
00189 conv_i420_2vuy_fun convertI420to2VUY;
00190
00191
00192 vector<VideoOutputQuartzView*> views;
00193
00194
00195 VideoOutputQuartzView * embeddedView;
00196 };
00197
00198 VideoOutputQuartzView::VideoOutputQuartzView(QuartzData *pData)
00199 : name(NULL), parentData(pData),
00200 thePort(NULL), theCodec(0), theMask(NULL), frameSkip(1), frameCounter(0),
00201 drawBlank(true), applyMoveResize(false)
00202 {
00203 }
00204
00205 VideoOutputQuartzView::~VideoOutputQuartzView()
00206 {
00207 End();
00208 }
00209
00212 bool VideoOutputQuartzView::Begin(void)
00213 {
00214 viewLock.lock();
00215 if (!thePort)
00216 {
00217 LOG(VB_GENERAL, LOG_ERR,
00218 QString("VOQV::Begin(%1) - No graphics port available")
00219 .arg(name));
00220 viewLock.unlock();
00221 return false;
00222 }
00223
00224
00225 Rect portBounds;
00226 GetPortBounds(thePort, &portBounds);
00227 LOG(VB_PLAYBACK, LOG_INFO, QString("%0Viewport currently %1,%2 -> %3,%4")
00228 .arg(name).arg(portBounds.left).arg(portBounds.top)
00229 .arg(portBounds.right).arg(portBounds.bottom));
00230 m_desired.setWidth(portBounds.right);
00231 m_desired.setHeight(portBounds.bottom);
00232 #if 0
00233
00234 theMask = NewRgn();
00235 SetRectRgn(theMask, m_desired.left(), m_desired.top(),
00236 m_desired.width(), m_desired.height());
00237 #endif
00238
00239
00240 if (DecompressSequenceBeginS(&theCodec,
00241 parentData->imgDesc,
00242 NULL,
00243 0,
00244 thePort,
00245 NULL,
00246 NULL,
00247 NULL,
00248 srcCopy,
00249 theMask,
00250 0,
00251 codecNormalQuality,
00252 bestSpeedCodec))
00253 {
00254 LOG(VB_GENERAL, LOG_ERR,
00255 QString("VOQV::Begin(%1) - DecompressSequenceBeginS failed")
00256 .arg(name));
00257 viewLock.unlock();
00258 return false;
00259 }
00260
00261
00262 if (!parentData->correctGamma)
00263 QTSetPixMapHandleRequestedGammaLevel(GetPortPixMap(thePort),
00264 kQTUseSourceGammaLevel);
00265
00266 SetDSequenceFlags(theCodec,
00267 codecDSequenceFlushInsteadOfDirtying,
00268 codecDSequenceFlushInsteadOfDirtying);
00269 viewLock.unlock();
00270
00271
00272 Transform(m_desired);
00273
00274 return true;
00275 }
00276
00278 void VideoOutputQuartzView::End(void)
00279 {
00280 viewLock.lock();
00281
00282 if (theCodec)
00283 {
00284 CDSequenceEnd(theCodec);
00285 theCodec = 0;
00286 if (theMask)
00287 {
00288 DisposeRgn(theMask);
00289 theMask = NULL;
00290 }
00291 }
00292 viewLock.unlock();
00293 }
00294
00296 void VideoOutputQuartzView::Transform(QRect newRect)
00297 {
00298 MatrixRecord matrix;
00299 SetIdentityMatrix(&matrix);
00300
00301 int x, y, w, h, sw, sh;
00302 x = newRect.left();
00303 y = newRect.top();
00304 w = newRect.width();
00305 h = newRect.height();
00306 sw = parentData->srcWidth;
00307 sh = parentData->srcHeight;
00308
00309
00310 Fixed one, zero;
00311 one = Long2Fix(1);
00312 zero = Long2Fix(0);
00313
00314 LOG(VB_PLAYBACK, LOG_INFO, QString("%0Viewport is %1 x %2")
00315 .arg(name).arg(w).arg(h));
00316 LOG(VB_PLAYBACK, LOG_INFO, QString("%0Image is %1 x %2")
00317 .arg(name).arg(sw).arg(sh));
00318
00319 double hscale = (double) w / sw;
00320 double vscale = (double) h / sh;
00321
00322
00323 if (!parentData->scaleUpVideo)
00324 {
00325 double maxScale = fmax(hscale, vscale);
00326 hscale /= maxScale;
00327 vscale /= maxScale;
00328 }
00329
00330 if ((hscale < 0.99) || (hscale > 1.01) ||
00331 (vscale < 0.99) || (vscale > 1.01))
00332 {
00333 LOG(VB_PLAYBACK, LOG_INFO, QString("%0Scaling to %1 x %2 of original")
00334 .arg(name).arg(hscale).arg(vscale));
00335 ScaleMatrix(&matrix,
00336 X2Fix(hscale),
00337 X2Fix(vscale),
00338 zero, zero);
00339
00340
00341 sw = (int)(sw * hscale);
00342 sh = (int)(sh * vscale);
00343 }
00344
00345
00346 if ((h != sh) || (w != sw))
00347 {
00348 LOG(VB_PLAYBACK, LOG_INFO, QString("%0Centering with %1, %2")
00349 .arg(name).arg((w - sw)/2.0).arg((h - sh)/2.0));
00350 TranslateMatrix(&matrix, X2Fix((w - sw) / 2.0), X2Fix((h - sh) / 2.0));
00351 }
00352
00353
00354 if (x || y)
00355 {
00356 LOG(VB_PLAYBACK, LOG_INFO, QString("%0Translating to %1, %2")
00357 .arg(name).arg(x).arg(y));
00358 TranslateMatrix(&matrix, Long2Fix(x), Long2Fix(y));
00359 }
00360
00361
00362 viewLock.lock();
00363 SetDSequenceMatrix(theCodec, &matrix);
00364 viewLock.unlock();
00365 BlankScreen(true);
00366 }
00367
00368 void VideoOutputQuartzView::BlankScreen(bool deferred)
00369 {
00370 if (deferred)
00371 {
00372 drawBlank = true;
00373 return;
00374 }
00375
00376 viewLock.lock();
00377 if (thePort)
00378 {
00379 SetPort(thePort);
00380
00381
00382 Rect clipRect;
00383 if (m_desired.width() && m_desired.height())
00384 {
00385 clipRect.left = m_desired.left();
00386 clipRect.top = m_desired.top();
00387 clipRect.right = m_desired.right();
00388 clipRect.bottom = m_desired.bottom();
00389 }
00390 else
00391 {
00392 GetPortBounds(thePort, &clipRect);
00393 }
00394 RgnHandle clipRgn = NewRgn();
00395 RectRgn(clipRgn, &clipRect);
00396
00397
00398 RGBColor rgbBlack = { 0, 0, 0 };
00399 RGBBackColor(&rgbBlack);
00400 EraseRect(&clipRect);
00401 QDFlushPortBuffer(thePort, clipRgn);
00402
00403 drawBlank = false;
00404 }
00405 viewLock.unlock();
00406 }
00407
00408 bool VideoOutputQuartzView::Init(void)
00409 {
00410 return (BeginPort() && Begin());
00411 }
00412
00413 void VideoOutputQuartzView::SetFrameSkip(int numskip)
00414 {
00415 frameSkip = numskip + 1;
00416 }
00417
00418 void VideoOutputQuartzView::Show(void)
00419 {
00420 if (drawBlank)
00421 BlankScreen(false);
00422
00423
00424
00425 frameCounter = (frameCounter + 1) % frameSkip;
00426 if (frameCounter)
00427 return;
00428
00429 viewLock.lock();
00430 if (theCodec && thePort && parentData->pixelData)
00431 {
00432 CodecFlags outFlags;
00433
00434
00435 if (DecompressSequenceFrameWhen(theCodec,
00436 (Ptr)parentData->pixelData,
00437 parentData->pixelSize,
00438 0,
00439 &outFlags,
00440 NULL,
00441 NULL))
00442 {
00443 LOG(VB_GENERAL, LOG_ERR,
00444 QString("VOQV::Show(%1)- DecompressSequenceFrameWhen failed")
00445 .arg(name));
00446 }
00447 }
00448 viewLock.unlock();
00449 }
00450
00451 void VideoOutputQuartzView::InputChanged(int width, int height, float aspect,
00452 MythCodecID av_codec_id)
00453 {
00454 (void)width;
00455 (void)height;
00456 (void)aspect;
00457 (void)av_codec_id;
00458
00459
00460 End();
00461 Begin();
00462 }
00463
00464 void VideoOutputQuartzView::MoveResize(QRect newRect)
00465 {
00466 if (applyMoveResize)
00467 Transform(newRect);
00468 }
00469
00472 void VideoOutputQuartzView::HideForGUI(void)
00473 {
00474
00475 }
00476
00479 void VideoOutputQuartzView::ShowAfterGUI(QRect size)
00480 {
00481
00482 }
00483
00487 class VoqvMainWindow : public VideoOutputQuartzView
00488 {
00489 public:
00490 VoqvMainWindow(QuartzData *pData, float alphaBlend = 1.0)
00491 : VideoOutputQuartzView(pData)
00492 {
00493 alpha = fminf(1.0, fmaxf(0.0, alphaBlend));
00494 applyMoveResize = true;
00495 name = (char *) "Main window: ";
00496 };
00497
00498 ~VoqvMainWindow()
00499 {
00500 End();
00501 EndPort();
00502 };
00503
00504 protected:
00505 float alpha;
00506
00507 bool BeginPort(void)
00508 {
00509 viewLock.lock();
00510 thePort = GetWindowPort(parentData->window);
00511 if (!thePort)
00512 {
00513 LOG(VB_GENERAL, LOG_ERR,
00514 "VoqvMainWindow::BeginPort() - GetWindowPort failed");
00515 viewLock.unlock();
00516 return false;
00517 }
00518
00519 SetWindowAlpha(parentData->window, alpha);
00520 RGBColor black = { 0, 0, 0 };
00521 SetWindowContentColor(parentData->window, &black);
00522 viewLock.unlock();
00523 return true;
00524 };
00525
00526 bool Begin(void)
00527 {
00528 bool ret = VideoOutputQuartzView::Begin();
00529
00530 if (ret && (alpha < 0.99))
00531 {
00532
00533 RGBColor black = { 0, 0, 0 };
00534 viewLock.lock();
00535 SetDSequenceTransferMode(theCodec, transparent, &black);
00536 viewLock.unlock();
00537 }
00538 return ret;
00539 };
00540
00541 void EndPort(void)
00542 {
00543 viewLock.lock();
00544 SetWindowAlpha(parentData->window, 1.0);
00545 thePort = NULL;
00546 viewLock.unlock();
00547 };
00548
00549 void HideForGUI(void)
00550 {
00551 LOG(VB_PLAYBACK, LOG_INFO, "VOQV::HideForGUI() main window");
00552 End();
00553 }
00554
00555 void ShowAfterGUI(QRect size)
00556 {
00557 LOG(VB_PLAYBACK, LOG_INFO, "VOQV::ShowAfterGUI() main window");
00558 Begin();
00559 Transform(size);
00560 }
00561 };
00562
00566 class VoqvEmbedded : public VideoOutputQuartzView
00567 {
00568 public:
00569 VoqvEmbedded(QuartzData *pData, int x, int y, int w, int h)
00570 : VideoOutputQuartzView(pData)
00571 {
00572 m_desired = QRect(x, y, w, h);
00573 name = (char *) "Embedded window: ";
00574 };
00575
00576 ~VoqvEmbedded()
00577 {
00578 End();
00579 EndPort();
00580 };
00581
00582 protected:
00583 bool BeginPort(void)
00584 {
00585 viewLock.lock();
00586 thePort = GetWindowPort(parentData->window);
00587 if (!thePort)
00588 {
00589 LOG(VB_GENERAL, LOG_ERR,
00590 "VoqvEmbedded::BeginPort() - GetWindowPort failed");
00591 viewLock.unlock();
00592 return false;
00593 }
00594
00595
00596 Rect portBounds;
00597 GetPortBounds(thePort, &portBounds);
00598 InvalWindowRect(parentData->window, &portBounds);
00599
00600 viewLock.unlock();
00601 return true;
00602 };
00603
00604
00605 bool Begin(void)
00606 {
00607 viewLock.lock();
00608 if (DecompressSequenceBeginS(&theCodec, parentData->imgDesc,
00609 NULL, 0, thePort, NULL, NULL, NULL,
00610 srcCopy, theMask, 0,
00611 codecNormalQuality, bestSpeedCodec))
00612 {
00613 LOG(VB_GENERAL, LOG_ERR,
00614 QString("VOQV::Begin(%1) - DecompressSequenceBeginS failed")
00615 .arg(name));
00616 viewLock.unlock();
00617 return false;
00618 }
00619
00620
00621 if (!parentData->correctGamma)
00622 QTSetPixMapHandleRequestedGammaLevel(GetPortPixMap(thePort),
00623 kQTUseSourceGammaLevel);
00624
00625 SetDSequenceFlags(theCodec,
00626 codecDSequenceFlushInsteadOfDirtying,
00627 codecDSequenceFlushInsteadOfDirtying);
00628 viewLock.unlock();
00629
00630
00631 Transform(m_desired);
00632
00633 return true;
00634 }
00635
00636 void EndPort(void)
00637 {
00638 viewLock.lock();
00639 thePort = NULL;
00640 viewLock.unlock();
00641 };
00642 };
00643
00647 class VoqvFullscreen : public VideoOutputQuartzView
00648 {
00649 public:
00650 VoqvFullscreen(QuartzData *pData)
00651 : VideoOutputQuartzView(pData)
00652 {
00653 applyMoveResize = true;
00654 name = (char *) "Full screen: ";
00655 };
00656
00657 ~VoqvFullscreen()
00658 {
00659 End();
00660 EndPort();
00661 };
00662
00663 protected:
00664 CGDirectDisplayID d;
00665
00666 bool BeginPort(void)
00667 {
00668 viewLock.lock();
00669 d = parentData->screen;
00670
00671 if (CGDisplayCapture(d) != CGDisplayNoErr)
00672 {
00673 LOG(VB_GENERAL, LOG_ERR,
00674 "VoqvFullScreen::BeginPort() - Could not capture display");
00675 viewLock.unlock();
00676 return false;
00677 }
00678
00679
00680 if (gCoreContext->GetNumSetting("UseVideoModes", 0))
00681 {
00682 DisplayRes *disp = DisplayRes::GetDisplayRes();
00683 disp->SwitchToVideo(parentData->srcWidth, parentData->srcHeight);
00684 }
00685
00686 CGDisplayHideCursor(d);
00687
00688 thePort = CreateNewPortForCGDisplayID((UInt32)d);
00689 if (!thePort)
00690 {
00691 LOG(VB_GENERAL, LOG_ERR, "VoqvFullScreen::BeginPort() - "
00692 "CreateNewPortForCGDisplayID failed");
00693 viewLock.unlock();
00694 return false;
00695 }
00696
00697 viewLock.unlock();
00698 return true;
00699 };
00700
00701 void EndPort(void)
00702 {
00703 viewLock.lock();
00704 if (thePort)
00705 {
00706 DisposePort(thePort);
00707 thePort = NULL;
00708 }
00709
00710
00711 if (gCoreContext->GetNumSetting("UseVideoModes", 0))
00712 DisplayRes::GetDisplayRes()->SwitchToGUI();
00713
00714 if (d)
00715 {
00716 CGDisplayShowCursor(d);
00717 CGDisplayRelease(d);
00718 d = NULL;
00719 }
00720 viewLock.unlock();
00721 };
00722
00723 void HideForGUI(void)
00724 {
00725 LOG(VB_PLAYBACK, LOG_INFO, "VOQV::HideForGUI() full screen");
00726 End();
00727 EndPort();
00728 }
00729
00730 void ShowAfterGUI(QRect size)
00731 {
00732 LOG(VB_PLAYBACK, LOG_INFO, "VOQV::ShowAfterGUI() full screen");
00733 BeginPort();
00734 Begin();
00735 Transform(size);
00736 }
00737 };
00738
00742 class VoqvDock : public VideoOutputQuartzView
00743 {
00744 public:
00745 VoqvDock(QuartzData *pData)
00746 : VideoOutputQuartzView(pData)
00747 {
00748 name = (char *) "Dock icon: ";
00749 };
00750
00751 ~VoqvDock()
00752 {
00753 End();
00754 EndPort();
00755 };
00756
00757 protected:
00758 bool BeginPort(void)
00759 {
00760 thePort = BeginQDContextForApplicationDockTile();
00761 if (!thePort)
00762 {
00763 LOG(VB_GENERAL, LOG_ERR, "VoqvDock::BeginPort() - "
00764 "BeginQDContextForApplicationDockTile failed");
00765 return false;
00766 }
00767 return true;
00768 };
00769
00770 void EndPort(void)
00771 {
00772 viewLock.lock();
00773 EndQDContextForApplicationDockTile(thePort);
00774 thePort = NULL;
00775 RestoreApplicationDockTileImage();
00776 viewLock.unlock();
00777 };
00778 };
00779
00784 class VoqvFloater : public VideoOutputQuartzView
00785 {
00786 public:
00787 VoqvFloater(QuartzData *pData, float alphaBlend = 0.5)
00788 : VideoOutputQuartzView(pData)
00789 {
00790 alpha = fminf(1.0, fmaxf(0.0, alphaBlend));
00791 resizing = false;
00792 name = (char *) "Floating window: ";
00793 };
00794
00795 ~VoqvFloater()
00796 {
00797 End();
00798 EndPort();
00799 };
00800
00801 void Show(void)
00802 {
00803 if (resizing)
00804 return;
00805
00806 VideoOutputQuartzView::Show();
00807 }
00808
00809 void ResizeChanged(bool startResizing)
00810 {
00811 if (!startResizing)
00812 {
00813
00814 Rect curBounds;
00815 GetPortBounds(thePort, &curBounds);
00816 m_desired.setWidth(curBounds.right - curBounds.left);
00817 m_desired.setHeight(curBounds.bottom - curBounds.top);
00818 SetRectRgn(theMask, m_desired.left(), m_desired.top(),
00819 m_desired.width(), m_desired.height());
00820 Transform(m_desired);
00821 }
00822 resizing = startResizing;
00823 }
00824
00825 protected:
00826 ToolboxObjectClassRef myClass;
00827 WindowRef window;
00828 float alpha;
00829 bool resizing;
00830
00831 bool BeginPort(void)
00832 {
00833 viewLock.lock();
00834
00835 Rect bounds;
00836 bounds.top = bounds.left = bounds.right = bounds.bottom = 50;
00837 switch ((int)(10 * parentData->srcAspect))
00838 {
00839 case 17:
00840 case 18:
00841 bounds.right += 320;
00842 bounds.bottom += 180;
00843 break;
00844 case 13:
00845 bounds.right += 280;
00846 bounds.bottom += 210;
00847 break;
00848 default:
00849 bounds.right += CGDisplayPixelsWide(parentData->screen) / 3;
00850 bounds.bottom += CGDisplayPixelsHigh(parentData->screen) / 3;
00851 }
00852
00853
00854 EventHandlerUPP myUPP = NewEventHandlerUPP(VoqvFloater_Callback);
00855 EventTypeSpec defEvents[] =
00856 { { kEventClassWindow, kEventWindowHitTest },
00857 { kEventClassWindow, kEventWindowDrawFrame },
00858 { kEventClassWindow, kEventWindowClickResizeRgn } };
00859 RegisterToolboxObjectClass(CFSTR("org.mythtv.myth.VoqvFloater"),
00860 NULL,
00861 3,
00862 defEvents,
00863 myUPP,
00864 this,
00865 &myClass);
00866 WindowDefSpec mySpec;
00867 mySpec.defType = kWindowDefObjectClass;
00868 mySpec.u.classRef = myClass;
00869 if (CreateCustomWindow(&mySpec,
00870 kUtilityWindowClass,
00871 kWindowNoShadowAttribute |
00872 kWindowResizableAttribute |
00873 kWindowStandardHandlerAttribute,
00874 &bounds,
00875 &window))
00876 {
00877 LOG(VB_GENERAL, LOG_ERR,
00878 "VoqvFloater::BeginPort() - CreateCustomWindow failed");
00879 viewLock.unlock();
00880 return false;
00881 }
00882 SetWindowAlpha(window, alpha);
00883 RGBColor black = { 0, 0, 0 };
00884 SetWindowContentColor(window, &black);
00885
00886 thePort = GetWindowPort(window);
00887 if (!thePort)
00888 {
00889 LOG(VB_GENERAL, LOG_ERR,
00890 "VoqvFloater::BeginPort() - GetWindowPort failed");
00891 viewLock.unlock();
00892 return false;
00893 }
00894
00895 viewLock.unlock();
00896 ShowWindow(window);
00897
00898 SelectWindow(parentData->window);
00899
00900 return true;
00901 };
00902
00903 bool Begin(void)
00904 {
00905 bool ret = VideoOutputQuartzView::Begin();
00906
00907 if (ret && (alpha < 0.99))
00908 {
00909
00910 RGBColor black = { 0, 0, 0 };
00911 viewLock.lock();
00912 SetDSequenceTransferMode(theCodec, transparent, &black);
00913 viewLock.unlock();
00914 }
00915 return ret;
00916 };
00917
00918 void EndPort(void)
00919 {
00920 viewLock.lock();
00921 thePort = NULL;
00922 if (window)
00923 {
00924 DisposeWindow(window);
00925 window = NULL;
00926 }
00927 UnregisterToolboxObjectClass(myClass);
00928 viewLock.unlock();
00929 };
00930 };
00931
00932
00933 OSStatus VoqvFloater_Callback(EventHandlerCallRef inHandlerCallRef,
00934 EventRef inEvent,
00935 void *inUserData)
00936 {
00937 (void)inHandlerCallRef;
00938 VoqvFloater *floater = reinterpret_cast<VoqvFloater*>(inUserData);
00939 WindowRef window;
00940 Point mouseLoc;
00941 Rect winLoc;
00942 WindowDefPartCode where;
00943
00944 switch (GetEventKind(inEvent))
00945 {
00946 case kEventWindowHitTest:
00947
00948 GetEventParameter(inEvent,
00949 kEventParamDirectObject,
00950 typeWindowRef,
00951 NULL,
00952 sizeof(WindowRef),
00953 NULL,
00954 &window);
00955 GetEventParameter(inEvent,
00956 kEventParamMouseLocation,
00957 typeQDPoint,
00958 NULL,
00959 sizeof(mouseLoc),
00960 NULL,
00961 &mouseLoc);
00962
00963
00964 GetWindowBounds(window,
00965 kWindowGlobalPortRgn,
00966 &winLoc);
00967 where = wInDrag;
00968 if (mouseLoc.h > (winLoc.right - 12) &&
00969 mouseLoc.v > (winLoc.bottom - 12))
00970 {
00971 where = wInGrow;
00972 }
00973 SetEventParameter(inEvent,
00974 kEventParamWindowDefPart,
00975 typeWindowDefPartCode,
00976 sizeof(WindowDefPartCode),
00977 &where);
00978 break;
00979
00980 case kEventWindowClickResizeRgn:
00981
00982 GetEventParameter(inEvent,
00983 kEventParamDirectObject,
00984 typeWindowRef,
00985 NULL,
00986 sizeof(WindowRef),
00987 NULL,
00988 &window);
00989 GetEventParameter(inEvent,
00990 kEventParamMouseLocation,
00991 typeQDPoint,
00992 NULL,
00993 sizeof(mouseLoc),
00994 NULL,
00995 &mouseLoc);
00996
00997 floater->ResizeChanged(true);
00998 ResizeWindow(window, mouseLoc, NULL, NULL);
00999 floater->ResizeChanged(false);
01000 break;
01001 }
01002 return noErr;
01003 }
01004
01005
01009 class VoqvDesktop : public VideoOutputQuartzView
01010 {
01011 public:
01012 VoqvDesktop(QuartzData *pData)
01013 : VideoOutputQuartzView(pData)
01014 {
01015 name = (char *) "Desktop: ";
01016 };
01017
01018 ~VoqvDesktop()
01019 {
01020 End();
01021 EndPort();
01022 };
01023
01024 protected:
01025 WindowRef window;
01026
01027 bool BeginPort(void)
01028 {
01029 viewLock.lock();
01030
01031 Rect bounds;
01032 bounds.top = bounds.left = 0;
01033 bounds.right = CGDisplayPixelsWide(parentData->screen);
01034 bounds.bottom = CGDisplayPixelsHigh(parentData->screen);
01035 if (CreateNewWindow(kPlainWindowClass,
01036 kWindowNoShadowAttribute |
01037 kWindowOpaqueForEventsAttribute,
01038 &bounds,
01039 &window))
01040 {
01041 LOG(VB_GENERAL, LOG_ERR,
01042 "VoqvDesktop::BeginPort() - CreateNewWindow failed");
01043 viewLock.unlock();
01044 return false;
01045 }
01046 WindowGroupRef winGroup;
01047 if (CreateWindowGroup(0, &winGroup))
01048 {
01049 LOG(VB_GENERAL, LOG_ERR,
01050 "VoqvDesktop::BeginPort() - CreateWindowGroup failed");
01051 viewLock.unlock();
01052 return false;
01053 }
01054 SetWindowGroupLevel(winGroup, kCGDesktopIconWindowLevel - 1);
01055 SetWindowGroup(window, winGroup);
01056 RGBColor black = { 0, 0, 0 };
01057 SetWindowContentColor(window, &black);
01058
01059 thePort = GetWindowPort(window);
01060 if (!thePort)
01061 {
01062 LOG(VB_GENERAL, LOG_ERR,
01063 "VoqvDesktop::BeginPort() - GetWindowPort failed");
01064 viewLock.unlock();
01065 return false;
01066 }
01067 viewLock.unlock();
01068 ShowWindow(window);
01069
01070 SelectWindow(parentData->window);
01071
01072 return true;
01073 };
01074
01075 void EndPort(void)
01076 {
01077 viewLock.lock();
01078 thePort = NULL;
01079 if (window)
01080 {
01081 DisposeWindow(window);
01082 window = NULL;
01083 }
01084 viewLock.unlock();
01085 };
01086 };
01087
01088 void VideoOutputQuartz::GetRenderOptions(render_opts &opts,
01089 QStringList &cpudeints)
01090 {
01091 opts.renderers->append("quartz-blit");
01092 opts.deints->insert("quartz-blit", cpudeints);
01093 (*opts.osds)["quartz-blit"].append("softblend");
01094 (*opts.safe_renderers)["dummy"].append("quartz-blit");
01095 (*opts.safe_renderers)["nuppel"].append("quartz-blit");
01096 if (opts.decoders->contains("ffmpeg"))
01097 (*opts.safe_renderers)["ffmpeg"].append("quartz-blit");
01098 if (opts.decoders->contains("vda"))
01099 (*opts.safe_renderers)["vda"].append("quartz-blit");
01100 if (opts.decoders->contains("crystalhd"))
01101 (*opts.safe_renderers)["crystalhd"].append("quartz-blit");
01102 (*opts.render_group)["quartz"].append("quartz-blit");
01103 opts.priorities->insert("quartz-blit", 70);
01104 }
01105
01109 VideoOutputQuartz::VideoOutputQuartz() :
01110 VideoOutput(), Started(false), data(new QuartzData())
01111 {
01112 init(&pauseFrame, FMT_YV12, NULL, 0, 0, 0, 0);
01113 }
01114
01115 VideoOutputQuartz::~VideoOutputQuartz()
01116 {
01117 if (data)
01118 {
01119 Exit();
01120
01121 delete data;
01122 data = NULL;
01123 }
01124 }
01125
01126 void VideoOutputQuartz::VideoAspectRatioChanged(float aspect)
01127 {
01128 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01129 QString("VideoAspectRatioChanged(aspect=%1) [was %2]")
01130 .arg(aspect).arg(data->srcAspect));
01131
01132 VideoOutput::VideoAspectRatioChanged(aspect);
01133
01134 data->srcAspect = aspect;
01135 data->srcMode = db_aspectoverride;
01136 }
01137
01138
01139 void VideoOutputQuartz::Zoom(ZoomDirection direction)
01140 {
01141 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01142 QString("Zoom(direction=%1)").arg(direction));
01143
01144 VideoOutput::Zoom(direction);
01145 MoveResize();
01146 }
01147
01148 void VideoOutputQuartz::ToggleAdjustFill(AdjustFillMode adjustFill)
01149 {
01150
01151 VideoOutput::ToggleAdjustFill(adjustFill);
01152
01153
01154
01155 data->views[0]->MoveResize(window.GetDisplayVideoRect());
01156 }
01157
01158 void VideoOutputQuartz::MoveResize(void)
01159 {
01160
01161
01162 VideoOutput::MoveResize();
01163
01164 QRect newRect = window.GetDisplayVideoRect();
01165
01166 vector<VideoOutputQuartzView*>::iterator it;
01167 for (it = data->views.begin(); it != data->views.end(); ++it)
01168 {
01169 (*it)->MoveResize(newRect);
01170 }
01171 }
01172
01173 void VideoOutputQuartz::ToggleAspectOverride(AspectOverrideMode aspectMode)
01174 {
01175 VideoOutput::ToggleAspectOverride(aspectMode);
01176 MoveResize();
01177 }
01178
01179 bool VideoOutputQuartz::InputChanged(const QSize &input_size,
01180 float aspect,
01181 MythCodecID av_codec_id,
01182 void *codec_private,
01183 bool &aspect_only)
01184 {
01185 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01186 QString("InputChanged(WxH = %1x%2, aspect=%3")
01187 .arg(input_size.width())
01188 .arg(input_size.height()).arg(aspect));
01189
01190 bool cid_changed = (video_codec_id != av_codec_id);
01191 bool res_changed = input_size != window.GetActualVideoDim();
01192 bool asp_changed = aspect != window.GetVideoAspect();
01193
01194 VideoOutput::InputChanged(input_size, aspect, av_codec_id, codec_private,
01195 aspect_only);
01196
01197 if (!res_changed && !cid_changed)
01198 {
01199 aspect_only = true;
01200
01201 if (asp_changed)
01202 {
01203 MoveResize();
01204 }
01205 return true;
01206 }
01207
01208 const QSize video_dim = window.GetVideoDispDim();
01209
01210 DeleteQuartzBuffers();
01211
01212 data->srcWidth = video_dim.width();
01213 data->srcHeight = video_dim.height();
01214 data->srcAspect = aspect;
01215 data->srcMode = db_aspectoverride;
01216
01217 CreateQuartzBuffers();
01218
01219 vector<VideoOutputQuartzView*>::iterator it = data->views.begin();
01220 for (; it != data->views.end(); ++it)
01221 {
01222 (*it)->InputChanged(
01223 video_dim.width(), video_dim.height(), aspect, av_codec_id);
01224 }
01225
01226 MoveResize();
01227
01228 return true;
01229 }
01230
01231 bool VideoOutputQuartz::Init(int width, int height, float aspect,
01232 WId winid, const QRect &win_rect,
01233 MythCodecID codec_id)
01234 {
01235 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01236 QString("Init(WxH %1x%2, aspect=%3, winid=%4\n\t\t\t"
01237 "win_bounds(x %5, y%6, WxH %7x%8))")
01238 .arg(width).arg(height).arg(aspect).arg(winid)
01239 .arg(win_rect.x()).arg(win_rect.y())
01240 .arg(win_rect.width()).arg(win_rect.height()));
01241
01242 vbuffers.Init(kNumBuffers, true, kNeedFreeFrames,
01243 kPrebufferFramesNormal, kPrebufferFramesSmall,
01244 kKeepPrebuffer);
01245 VideoOutput::Init(width, height, aspect, winid, win_rect, codec_id);
01246
01247 const QSize video_dim = window.GetVideoDim();
01248 data->srcWidth = video_dim.width();
01249 data->srcHeight = video_dim.height();
01250 data->srcAspect = aspect;
01251 data->srcMode = db_aspectoverride;
01252
01253
01254 if (EnterMovies())
01255 {
01256 LOG(VB_GENERAL, LOG_ERR, LOC + "Init() - EnterMovies failed");
01257 return false;
01258 }
01259
01260
01261 data->window = FrontNonFloatingWindow();
01262 if (!data->window)
01263 {
01264 LOG(VB_GENERAL, LOG_ERR, LOC + "Init() - Find window failed");
01265 return false;
01266 }
01267
01268
01269
01270
01271
01272 if (GetWindowBounds(data->window,
01273 kWindowStructureRgn, &(data->windowBounds)))
01274 {
01275 LOG(VB_GENERAL, LOG_ERR, LOC + "Init() - GetWindowBounds failed");
01276 return false;
01277 }
01278 CGPoint pt;
01279 pt.x = data->windowBounds.left;
01280 pt.y = data->windowBounds.top;
01281 CGDisplayCount ct;
01282 data->screen = NULL;
01283 if (CGGetDisplaysWithPoint(pt, 1, &data->screen, &ct))
01284 {
01285
01286 data->screen = CGMainDisplayID();
01287 }
01288
01289
01290 CFDictionaryRef m;
01291 m = CGDisplayCurrentMode(data->screen);
01292 data->refreshRate = get_float_CF(m, kCGDisplayRefreshRate);
01293 if (data->refreshRate == 0.0)
01294 data->refreshRate = 150.0;
01295
01296
01297
01298 CGSize size_in_mm = CGDisplayScreenSize(data->screen);
01299 if ((size_in_mm.width > 0.0001f) && (size_in_mm.height > 0.0001f))
01300 {
01301 window.SetDisplayDim(QSize((uint) size_in_mm.width,
01302 (uint) size_in_mm.height));
01303 window.SetDisplayAspect(size_in_mm.width / size_in_mm.height);
01304 LOG(VB_PLAYBACK, LOG_INFO,
01305 QString("Screen size is %1 x %2 (mm), aspect %3")
01306 .arg(size_in_mm.width).arg(size_in_mm.height)
01307 .arg(size_in_mm.width / size_in_mm.height));
01308 }
01309
01310
01311 data->scaleUpVideo = gCoreContext->GetNumSetting("MacScaleUp", 1);
01312 data->drawInWindow = gCoreContext->GetNumSetting("GuiSizeForTV", 0);
01313 data->windowedMode = gCoreContext->GetNumSetting("RunFrontendInWindow", 0);
01314 data->correctGamma = gCoreContext->GetNumSetting("MacGammaCorrect", 0);
01315
01316 data->convertI420to2VUY = get_i420_2vuy_conv();
01317
01318
01319 if (data->drawInWindow)
01320 {
01321
01322 float winWidth = size_in_mm.width * win_rect.width()
01323 / get_int_CF(m, kCGDisplayWidth);
01324 float winHeight = size_in_mm.height * win_rect.height()
01325 / get_int_CF(m, kCGDisplayHeight);
01326 window.SetDisplayDim(QSize(winWidth, winHeight));
01327 window.SetDisplayAspect(winWidth / winHeight);
01328 LOG(VB_PLAYBACK, LOG_INFO,
01329 QString("Main window is %1 x %2 (mm), aspect %3")
01330 .arg((int)winWidth).arg((int)winHeight)
01331 .arg(winWidth / winHeight));
01332 }
01333
01334 if (!CreateQuartzBuffers())
01335 {
01336 LOG(VB_GENERAL, LOG_ERR, LOC + "Init() - CreateQuartzBuffers failed");
01337 return false;
01338 }
01339
01340
01341
01342 VideoOutputQuartzView *tmp;
01343 if (!data->drawInWindow)
01344 {
01345
01346 tmp = new VoqvFullscreen(data);
01347 tmp->SetFrameSkip(gCoreContext->GetNumSetting("MacFullSkip", 0));
01348 data->views.push_back(tmp);
01349 }
01350 else if (!data->windowedMode)
01351 {
01352
01353 tmp = new VoqvMainWindow(data, 1.0);
01354 tmp->SetFrameSkip(gCoreContext->GetNumSetting("MacFullSkip", 0));
01355 data->views.push_back(tmp);
01356 }
01357 else
01358 {
01359
01360 if (gCoreContext->GetNumSetting("MacMainEnabled", 1))
01361 {
01362 float opacity =
01363 gCoreContext->GetNumSetting("MacMainOpacity", 100) / 100.0;
01364 tmp = new VoqvMainWindow(data, opacity);
01365 tmp->SetFrameSkip(gCoreContext->GetNumSetting("MacMainSkip", 0));
01366 data->views.push_back(tmp);
01367 }
01368 else
01369 {
01370
01371
01372 LOG(VB_PLAYBACK, LOG_INFO, "Shrinking Main Window to 1x1");
01373 SizeWindow(data->window, 1, 1, true);
01374 }
01375 if (gCoreContext->GetNumSetting("MacFloatEnabled", 0))
01376 {
01377 float opacity =
01378 gCoreContext->GetNumSetting("MacFloatOpacity", 100) / 100.0;
01379 tmp = new VoqvFloater(data, opacity);
01380 tmp->SetFrameSkip(gCoreContext->GetNumSetting("MacFloatSkip", 0));
01381 data->views.push_back(tmp);
01382 }
01383 if (gCoreContext->GetNumSetting("MacDesktopEnabled", 0))
01384 {
01385 tmp = new VoqvDesktop(data);
01386 tmp->SetFrameSkip(gCoreContext->GetNumSetting("MacDesktopSkip", 0));
01387 data->views.push_back(tmp);
01388 }
01389 if (gCoreContext->GetNumSetting("MacDockEnabled", 1))
01390 {
01391 tmp = new VoqvDock(data);
01392 tmp->SetFrameSkip(gCoreContext->GetNumSetting("MacDockSkip", 3));
01393 data->views.push_back(tmp);
01394 }
01395 }
01396
01397 vector<VideoOutputQuartzView*>::iterator it = data->views.begin();
01398 for (; it != data->views.end(); ++it)
01399 {
01400 if (!(*it)->Init())
01401 {
01402 LOG(VB_GENERAL, LOG_ERR, LOC + "Init() - QuartzView Init() failed");
01403 }
01404 }
01405
01406 MoveResize();
01407 Started = true;
01408
01409 return true;
01410 }
01411
01412 void VideoOutputQuartz::SetVideoFrameRate(float playback_fps)
01413 {
01414 LOG(VB_PLAYBACK, LOG_INFO, QString("SetVideoFrameRate(%1) - unimplemented?")
01415 .arg(playback_fps));
01416 }
01417
01418 static QString toCommaList(const QStringList &list)
01419 {
01420 QString ret = "";
01421 for (QStringList::const_iterator it = list.begin(); it != list.end(); ++it)
01422 ret += *it + ",";
01423
01424 if (ret.length())
01425 return ret.left(ret.length()-1);
01426
01427 return "";
01428 }
01429
01430 bool VideoOutputQuartz::CreateQuartzBuffers(void)
01431 {
01432 const QSize video_dim = window.GetVideoDim();
01433 db_vdisp_profile->SetInput(video_dim);
01434 QStringList renderers = GetAllowedRenderers(video_codec_id, video_dim);
01435 QString renderer = QString::null;
01436
01437 QString tmp = db_vdisp_profile->GetVideoRenderer();
01438 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01439 QString("CreateQuartzBuffers() render: %1, allowed: %2")
01440 .arg(tmp).arg(toCommaList(renderers)));
01441
01442 if (renderers.contains(tmp))
01443 renderer = tmp;
01444 else if (!renderers.empty())
01445 renderer = renderers[0];
01446 else
01447 {
01448 LOG(VB_GENERAL, LOG_ERR, "Failed to find a video renderer");
01449 return false;
01450 }
01451
01452
01453 db_vdisp_profile->SetVideoRenderer(renderer);
01454 LOG(VB_GENERAL, LOG_INFO, LOC + "VProf: " + db_vdisp_profile->toString());
01455
01456 vbuffers.CreateBuffers(FMT_YV12, video_dim.width(), video_dim.height());
01457
01458
01459 if (pauseFrame.buf)
01460 delete [] pauseFrame.buf;
01461
01462 VideoFrame *scratch = vbuffers.GetScratchFrame();
01463
01464 init(&pauseFrame, FMT_YV12, new unsigned char[scratch->size],
01465 scratch->width, scratch->height, scratch->size);
01466
01467 pauseFrame.frameNumber = scratch->frameNumber;
01468
01469
01470
01471 data->pixelLock.lock();
01472
01473 int width, height;
01474 width = data->srcWidth;
01475 height = data->srcHeight;
01476
01477
01478
01479
01480 data->imgDesc =
01481 (ImageDescriptionHandle) NewHandleClear(sizeof(ImageDescription));
01482 HLock((Handle)(data->imgDesc));
01483
01484 ImageDescription *desc = *data->imgDesc;
01485
01486 desc->idSize = sizeof(ImageDescription);
01487 desc->cType = k422YpCbCr8CodecType;
01488 desc->version = 2;
01489 desc->revisionLevel = 0;
01490 desc->spatialQuality = codecNormalQuality;
01491 desc->width = width;
01492 desc->height = height;
01493 desc->hRes = Long2Fix(72);
01494 desc->vRes = Long2Fix(72);
01495 desc->depth = 24;
01496 desc->frameCount = 0;
01497 desc->dataSize = 0;
01498 desc->clutID = -1;
01499
01500 HUnlock((Handle)(data->imgDesc));
01501
01502
01503 data->pixelSize = width * height * 2;
01504 data->pixelData = new char[data->pixelSize];
01505
01506 data->pixelLock.unlock();
01507
01508 return true;
01509 }
01510
01511 void VideoOutputQuartz::Exit(void)
01512 {
01513 if (Started)
01514 {
01515 Started = false;
01516
01517
01518
01519 if (data->windowedMode)
01520 {
01521 LOG(VB_PLAYBACK, LOG_INFO,
01522 QString("Restoring Main Window to %1x%2")
01523 .arg(data->windowBounds.right - data->windowBounds.left)
01524 .arg(data->windowBounds.bottom - data->windowBounds.top));
01525 SetWindowBounds(data->window, kWindowStructureRgn,
01526 &(data->windowBounds));
01527 }
01528
01529 data->ClearViews();
01530 DeleteQuartzBuffers();
01531 }
01532 }
01533
01534 void VideoOutputQuartz::DeleteQuartzBuffers()
01535 {
01536 data->pixelLock.lock();
01537 if (data->imgDesc)
01538 {
01539 DisposeHandle((Handle)(data->imgDesc));
01540 data->imgDesc = NULL;
01541 }
01542 if (data->pixelData)
01543 {
01544 delete [] data->pixelData;
01545 data->pixelData = NULL;
01546 data->pixelSize = 0;
01547 }
01548 data->pixelLock.unlock();
01549
01550 if (pauseFrame.buf)
01551 {
01552 delete [] pauseFrame.buf;
01553 init(&pauseFrame, FMT_YV12, NULL, 0, 0, 0, 0);
01554 }
01555
01556 vbuffers.DeleteBuffers();
01557 }
01558
01559 void VideoOutputQuartz::EmbedInWidget(const QRect &rect)
01560 {
01561 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01562 QString("EmbedInWidget(x=%1, y=%2, w=%3, h=%4)")
01563 .arg(rect.left()).arg(rect.top())
01564 .arg(rect.width()).arg(rect.height()));
01565
01566 if (window.IsEmbedding())
01567 return;
01568
01569 VideoOutput::EmbedInWidget(rect);
01570
01571
01572 QRect newArea = window.GetDisplayVideoRect();
01573 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01574 QString("now - EmbedInWidget(x=%1, y=%2, w=%3, h=%4)")
01575 .arg(newArea.left()).arg(newArea.top())
01576 .arg(newArea.width()).arg(newArea.height()));
01577
01578 data->pixelLock.lock();
01579
01580
01581 data->embeddedView = new VoqvEmbedded(data, newArea.left(), newArea.top(),
01582 newArea.width(), newArea.height());
01583 if (data->embeddedView)
01584 {
01585 data->embeddedView->Init();
01586 data->views.push_back(data->embeddedView);
01587 }
01588
01589 data->pixelLock.unlock();
01590 }
01591
01592 void VideoOutputQuartz::StopEmbedding(void)
01593 {
01594 LOG(VB_PLAYBACK, LOG_INFO, LOC + "StopEmbedding()");
01595
01596 if (!window.IsEmbedding())
01597 return;
01598
01599 VideoOutput::StopEmbedding();
01600
01601 data->pixelLock.lock();
01602
01603
01604 if (data->embeddedView)
01605 {
01606 vector<VideoOutputQuartzView*>::iterator it =
01607 find(data->views.begin(), data->views.end(), data->embeddedView);
01608 if (it != data->views.end())
01609 {
01610 delete *it;
01611 data->views.erase(it);
01612 }
01613 data->embeddedView = NULL;
01614 }
01615
01616 data->pixelLock.unlock();
01617 }
01618
01622 void VideoOutputQuartz::PrepareFrame(VideoFrame *buffer, FrameScanType t,
01623 OSD *osd)
01624 {
01625 (void)osd;
01626 (void)t;
01627
01628 if (buffer)
01629 framesPlayed = buffer->frameNumber + 1;
01630 }
01631
01636 void VideoOutputQuartz::Show(FrameScanType t)
01637 {
01638 (void)t;
01639
01640 data->pixelLock.lock();
01641 vector<VideoOutputQuartzView*>::iterator it = data->views.begin();
01642 for (; it != data->views.end(); ++it)
01643 (*it)->Show();
01644 data->pixelLock.unlock();
01645 }
01646
01647 void VideoOutputQuartz::DrawUnusedRects(bool)
01648 {
01649 }
01650
01651 void VideoOutputQuartz::UpdatePauseFrame(int64_t &disp_timecode)
01652 {
01653 if (!pauseFrame.buf)
01654 {
01655 LOG(VB_GENERAL, LOG_ERR, LOC + "UpdatePauseFrame() - no buffers?");
01656 return;
01657 }
01658
01659 VideoFrame *pauseb = vbuffers.GetScratchFrame();
01660 VideoFrame *pauseu = vbuffers.head(kVideoBuffer_used);
01661 if (pauseu)
01662 CopyFrame(&pauseFrame, pauseu);
01663 else
01664 CopyFrame(&pauseFrame, pauseb);
01665
01666 disp_timecode = pauseFrame.disp_timecode;
01667 }
01668
01673 void VideoOutputQuartz::ProcessFrame(VideoFrame *frame, OSD *osd,
01674 FilterChain *filterList,
01675 const PIPMap &pipPlayers,
01676 FrameScanType scan)
01677 {
01678 if (!frame)
01679 {
01680 frame = vbuffers.GetScratchFrame();
01681 CopyFrame(vbuffers.GetScratchFrame(), &pauseFrame);
01682 }
01683
01684 if (filterList)
01685 filterList->ProcessFrame(frame);
01686
01687 if (m_deinterlacing &&
01688 m_deintFilter != NULL &&
01689 m_deinterlaceBeforeOSD)
01690 {
01691 m_deintFilter->ProcessFrame(frame, scan);
01692 }
01693
01694 ShowPIPs(frame, pipPlayers);
01695 if (osd && !window.IsEmbedding())
01696 DisplayOSD(frame, osd);
01697
01698 if (m_deinterlacing &&
01699 m_deintFilter != NULL &&
01700 !m_deinterlaceBeforeOSD)
01701 {
01702 m_deintFilter->ProcessFrame(frame, scan);
01703 }
01704
01705 QMutexLocker locker(&data->pixelLock);
01706 if (!data->pixelData)
01707 {
01708 LOG(VB_PLAYBACK, LOG_ERR, LOC + "ProcessFrame(): NULL pixelData!");
01709 return;
01710 }
01711
01712
01713 data->convertI420to2VUY(
01714 (unsigned char*) data->pixelData, frame->width<<1,
01715 frame->buf + frame->offsets[0],
01716 frame->buf + frame->offsets[1],
01717 frame->buf + frame->offsets[2],
01718 frame->pitches[0], frame->pitches[1], frame->pitches[2],
01719 frame->width, frame->height);
01720 }
01721
01723 void VideoOutputQuartz::ResizeForGui(void)
01724 {
01725 data->pixelLock.lock();
01726 vector<VideoOutputQuartzView*>::iterator it = data->views.begin();
01727 for (; it != data->views.end(); ++it)
01728 (*it)->HideForGUI();
01729 data->pixelLock.unlock();
01730
01731 VideoOutput::ResizeForGui();
01732 }
01733
01735 void VideoOutputQuartz::ResizeForVideo(uint width, uint height)
01736 {
01737 VideoOutput::ResizeForVideo(width, height);
01738
01739
01740 QRect size = window.GetDisplayVideoRect();
01741
01742 data->pixelLock.lock();
01743 vector<VideoOutputQuartzView*>::iterator it = data->views.begin();
01744 for (; it != data->views.end(); ++it)
01745 (*it)->ShowAfterGUI(size);
01746 data->pixelLock.unlock();
01747 }
01748
01749 QStringList VideoOutputQuartz::GetAllowedRenderers(
01750 MythCodecID myth_codec_id, const QSize &video_dim)
01751 {
01752 (void) video_dim;
01753
01754 QStringList list;
01755
01756 if (codec_is_std(myth_codec_id))
01757 {
01758 list += "quartz-blit";
01759 }
01760
01761 return list;
01762 }
01763
01764 MythCodecID VideoOutputQuartz::GetBestSupportedCodec(
01765 uint width, uint height,
01766 uint osd_width, uint osd_height,
01767 uint stream_type, uint fourcc)
01768 {
01769 (void) osd_width;
01770 (void) osd_height;
01771
01772 VideoDisplayProfile vdp;
01773 vdp.SetInput(QSize(width, height));
01774 QString dec = vdp.GetDecoder();
01775 if (dec == "ffmpeg")
01776 return (MythCodecID)(kCodec_MPEG1 + (stream_type-1));
01777 return (MythCodecID)(kCodec_MPEG1 + (stream_type-1));
01778 }