home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / Riza / source / displaygdi.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  14.0 KB  |  494 lines

  1. #include <windows.h>
  2. #include <vd2/system/binary.h>
  3. #include <vd2/system/vectors.h>
  4. #include <vd2/system/VDString.h>
  5. #include <vd2/Kasumi/pixmap.h>
  6. #include <vd2/Kasumi/pixmapops.h>
  7. #include <vd2/Kasumi/pixmaputils.h>
  8. #include "displaydrv.h"
  9.  
  10. #define VDDEBUG_DISP (void)sizeof printf
  11. //#define VDDEBUG_DISP VDDEBUG
  12.  
  13. void VDDitherImage(VDPixmap& dst, const VDPixmap& src, const uint8 *pLogPal);
  14.  
  15. ///////////////////////////////////////////////////////////////////////////////
  16.  
  17. class VDVideoDisplayMinidriverGDI : public VDVideoDisplayMinidriver {
  18. public:
  19.     VDVideoDisplayMinidriverGDI();
  20.     ~VDVideoDisplayMinidriverGDI();
  21.  
  22.     bool Init(HWND hwnd, const VDVideoDisplaySourceInfo& info);
  23.     void Shutdown();
  24.  
  25.     bool ModifySource(const VDVideoDisplaySourceInfo& info);
  26.  
  27.     bool IsValid() { return mbValid; }
  28.  
  29.     bool Update(UpdateMode);
  30.     void Refresh(UpdateMode);
  31.     bool Paint(HDC hdc, const RECT& rClient, UpdateMode mode);
  32.     bool SetSubrect(const vdrect32 *r);
  33.     void SetLogicalPalette(const uint8 *pLogicalPalette) { mpLogicalPalette = pLogicalPalette; }
  34.  
  35. protected:
  36.     HWND        mhwnd;
  37.     HDC            mhdc;
  38.     HBITMAP        mhbm;
  39.     HGDIOBJ        mhbmOld;
  40.     void *        mpBitmapBits;
  41.     ptrdiff_t    mPitch;
  42.     HPALETTE    mpal;
  43.     const uint8 *mpLogicalPalette;
  44.     bool        mbPaletted;
  45.     bool        mbValid;
  46.     bool        mbUseSubrect;
  47.     int            mScreenFormat;
  48.  
  49.     vdrect32    mSubrect;
  50.  
  51.     uint8        mIdentTab[256];
  52.  
  53.     VDVideoDisplaySourceInfo    mSource;
  54.  
  55.     void InternalRefresh(HDC hdc, const RECT& rClient, UpdateMode mode);
  56.     static int GetScreenIntermediatePixmapFormat(HDC);
  57. };
  58.  
  59. IVDVideoDisplayMinidriver *VDCreateVideoDisplayMinidriverGDI() {
  60.     return new VDVideoDisplayMinidriverGDI;
  61. }
  62.  
  63. VDVideoDisplayMinidriverGDI::VDVideoDisplayMinidriverGDI()
  64.     : mhwnd(0)
  65.     , mhdc(0)
  66.     , mhbm(0)
  67.     , mpal(0)
  68.     , mpLogicalPalette(NULL)
  69.     , mbValid(false)
  70.     , mbUseSubrect(false)
  71. {
  72.     memset(&mSource, 0, sizeof mSource);
  73. }
  74.  
  75. VDVideoDisplayMinidriverGDI::~VDVideoDisplayMinidriverGDI() {
  76. }
  77.  
  78. bool VDVideoDisplayMinidriverGDI::Init(HWND hwnd, const VDVideoDisplaySourceInfo& info) {
  79.     switch(info.pixmap.format) {
  80.     case nsVDPixmap::kPixFormat_Pal8:
  81.     case nsVDPixmap::kPixFormat_XRGB1555:
  82.     case nsVDPixmap::kPixFormat_RGB565:
  83.     case nsVDPixmap::kPixFormat_RGB888:
  84.     case nsVDPixmap::kPixFormat_XRGB8888:
  85.         break;
  86.  
  87.     case nsVDPixmap::kPixFormat_YUV422_YUYV:
  88.     case nsVDPixmap::kPixFormat_YUV422_UYVY:
  89.     case nsVDPixmap::kPixFormat_YUV444_Planar:
  90.     case nsVDPixmap::kPixFormat_YUV422_Planar:
  91.     case nsVDPixmap::kPixFormat_YUV420_Planar:
  92.     case nsVDPixmap::kPixFormat_YUV411_Planar:
  93.     case nsVDPixmap::kPixFormat_YUV410_Planar:
  94.     case nsVDPixmap::kPixFormat_Y8:
  95.     case nsVDPixmap::kPixFormat_YUV422_V210:
  96.     case nsVDPixmap::kPixFormat_YUV422_UYVY_709:
  97.     case nsVDPixmap::kPixFormat_YUV420_NV12:
  98.         if (!info.bAllowConversion)
  99.     default:
  100.             return false;
  101.     }
  102.     
  103.     mhwnd    = hwnd;
  104.     mSource    = info;
  105.  
  106.     if (HDC hdc = GetDC(mhwnd)) {
  107.         mScreenFormat = GetScreenIntermediatePixmapFormat(hdc);
  108.  
  109.         mhdc = CreateCompatibleDC(hdc);
  110.  
  111.         if (mhdc) {
  112.             bool bPaletted = 0 != (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE);
  113.  
  114.             mbPaletted = bPaletted;
  115.  
  116.             if (bPaletted) {
  117.                 struct {
  118.                     BITMAPINFOHEADER hdr;
  119.                     RGBQUAD pal[256];
  120.                 } bih;
  121.  
  122.                 bih.hdr.biSize            = sizeof(BITMAPINFOHEADER);
  123.                 bih.hdr.biWidth            = mSource.pixmap.w;
  124.                 bih.hdr.biHeight        = mSource.pixmap.h;
  125.                 bih.hdr.biPlanes        = 1;
  126.                 bih.hdr.biCompression    = BI_RGB;
  127.                 bih.hdr.biBitCount        = 8;
  128.  
  129.                 mPitch = ((mSource.pixmap.w + 3) & ~3);
  130.                 bih.hdr.biSizeImage        = mPitch * mSource.pixmap.h;
  131.                 bih.hdr.biClrUsed        = 216;
  132.                 bih.hdr.biClrImportant    = 216;
  133.  
  134.                 for(int i=0; i<216; ++i) {
  135.                     bih.pal[i].rgbRed    = (BYTE)((i / 36) * 51);
  136.                     bih.pal[i].rgbGreen    = (BYTE)(((i%36) / 6) * 51);
  137.                     bih.pal[i].rgbBlue    = (BYTE)((i%6) * 51);
  138.                     bih.pal[i].rgbReserved = 0;
  139.                 }
  140.  
  141.                 for(int j=0; j<256; ++j)
  142.                     mIdentTab[j] = (uint8)j;
  143.  
  144.                 mhbm = CreateDIBSection(hdc, (const BITMAPINFO *)&bih, DIB_RGB_COLORS, &mpBitmapBits, mSource.pSharedObject, mSource.sharedOffset);
  145.             } else if (mSource.pixmap.format == nsVDPixmap::kPixFormat_Pal8) {
  146.                 struct {
  147.                     BITMAPINFOHEADER hdr;
  148.                     RGBQUAD pal[256];
  149.                 } bih;
  150.  
  151.                 bih.hdr.biSize            = sizeof(BITMAPINFOHEADER);
  152.                 bih.hdr.biWidth            = mSource.pixmap.w;
  153.                 bih.hdr.biHeight        = mSource.pixmap.h;
  154.                 bih.hdr.biPlanes        = 1;
  155.                 bih.hdr.biCompression    = BI_RGB;
  156.                 bih.hdr.biBitCount        = 8;
  157.  
  158.                 mPitch = ((mSource.pixmap.w + 3) & ~3);
  159.                 bih.hdr.biSizeImage        = mPitch * mSource.pixmap.h;
  160.                 bih.hdr.biClrUsed        = 256;
  161.                 bih.hdr.biClrImportant    = 256;
  162.  
  163.                 for(int i=0; i<256; ++i) {
  164.                     bih.pal[i].rgbRed    = (uint8)(mSource.pixmap.palette[i] >> 16);
  165.                     bih.pal[i].rgbGreen    = (uint8)(mSource.pixmap.palette[i] >> 8);
  166.                     bih.pal[i].rgbBlue    = (uint8)mSource.pixmap.palette[i];
  167.                     bih.pal[i].rgbReserved = 0;
  168.                 }
  169.  
  170.                 mhbm = CreateDIBSection(hdc, (const BITMAPINFO *)&bih, DIB_RGB_COLORS, &mpBitmapBits, mSource.pSharedObject, mSource.sharedOffset);
  171.             } else {
  172.                 BITMAPV4HEADER bih = {0};
  173.  
  174.                 bih.bV4Size                = sizeof(BITMAPINFOHEADER);
  175.                 bih.bV4Width            = mSource.pixmap.w;
  176.                 bih.bV4Height            = mSource.pixmap.h;
  177.                 bih.bV4Planes            = 1;
  178.                 bih.bV4V4Compression    = BI_RGB;
  179.                 bih.bV4BitCount            = (WORD)(mSource.bpp << 3);
  180.  
  181.                 switch(mSource.pixmap.format) {
  182.                 case nsVDPixmap::kPixFormat_XRGB1555:
  183.                 case nsVDPixmap::kPixFormat_RGB888:
  184.                 case nsVDPixmap::kPixFormat_XRGB8888:
  185.                     break;
  186.                 case nsVDPixmap::kPixFormat_YUV422_YUYV:
  187.                 case nsVDPixmap::kPixFormat_YUV422_UYVY:
  188.                 case nsVDPixmap::kPixFormat_YUV444_Planar:
  189.                 case nsVDPixmap::kPixFormat_YUV422_Planar:
  190.                 case nsVDPixmap::kPixFormat_YUV420_Planar:
  191.                 case nsVDPixmap::kPixFormat_YUV411_Planar:
  192.                 case nsVDPixmap::kPixFormat_YUV410_Planar:
  193.                 case nsVDPixmap::kPixFormat_Y8:
  194.                 case nsVDPixmap::kPixFormat_YUV422_V210:
  195.                 case nsVDPixmap::kPixFormat_YUV422_UYVY_709:
  196.                 case nsVDPixmap::kPixFormat_YUV420_NV12:
  197.                 case nsVDPixmap::kPixFormat_RGB565:
  198.                     switch(mScreenFormat) {
  199.                     case nsVDPixmap::kPixFormat_XRGB1555:
  200.                         bih.bV4BitCount            = 16;
  201.                         break;
  202.                     case nsVDPixmap::kPixFormat_RGB565:
  203.                         bih.bV4V4Compression    = BI_BITFIELDS;
  204.                         bih.bV4RedMask            = 0xf800;
  205.                         bih.bV4GreenMask        = 0x07e0;
  206.                         bih.bV4BlueMask            = 0x001f;
  207.                         bih.bV4BitCount            = 16;
  208.                         break;
  209.                     case nsVDPixmap::kPixFormat_RGB888:
  210.                         bih.bV4BitCount            = 24;
  211.                         break;
  212.                     case nsVDPixmap::kPixFormat_XRGB8888:
  213.                         bih.bV4BitCount            = 32;
  214.                         break;
  215.                     }
  216.                     break;
  217.                 default:
  218.                     return false;
  219.                 }
  220.  
  221.                 mPitch = ((mSource.pixmap.w * bih.bV4BitCount + 31)>>5)*4;
  222.                 bih.bV4SizeImage        = mPitch * mSource.pixmap.h;
  223.                 mhbm = CreateDIBSection(hdc, (const BITMAPINFO *)&bih, DIB_RGB_COLORS, &mpBitmapBits, mSource.pSharedObject, mSource.sharedOffset);
  224.             }
  225.  
  226.             if (mhbm) {
  227.                 mhbmOld = SelectObject(mhdc, mhbm);
  228.  
  229.                 if (mhbmOld) {
  230.                     ReleaseDC(mhwnd, hdc);
  231.                     VDDEBUG_DISP("VideoDisplay: Using GDI for %dx%d %s display.\n", mSource.pixmap.w, mSource.pixmap.h, VDPixmapGetInfo(mSource.pixmap.format).name);
  232.                     mbValid = (mSource.pSharedObject != 0);
  233.                     return true;
  234.                 }
  235.  
  236.                 if (mSource.pSharedObject && mSource.sharedOffset >= 65536)
  237.                     UnmapViewOfFile(mpBitmapBits);        // Workaround for GDI memory leak in NT4
  238.  
  239.                 DeleteObject(mhbm);
  240.                 mhbm = 0;
  241.             }
  242.             DeleteDC(mhdc);
  243.             mhdc = 0;
  244.         }
  245.  
  246.         ReleaseDC(mhwnd, hdc);
  247.     }
  248.  
  249.     Shutdown();
  250.     return false;
  251. }
  252.  
  253. void VDVideoDisplayMinidriverGDI::Shutdown() {
  254.     if (mhbm) {
  255.         SelectObject(mhdc, mhbmOld);
  256.         DeleteObject(mhbm);
  257.         if (mSource.pSharedObject && mSource.sharedOffset >= 65536)
  258.             UnmapViewOfFile(mpBitmapBits);        // Workaround for GDI memory leak in NT4
  259.         mhbm = 0;
  260.     }
  261.  
  262.     if (mhdc) {
  263.         DeleteDC(mhdc);
  264.         mhdc = 0;
  265.     }
  266.  
  267.     mbValid = false;
  268. }
  269.  
  270. bool VDVideoDisplayMinidriverGDI::ModifySource(const VDVideoDisplaySourceInfo& info) {
  271.     if (!mhdc)
  272.         return false;
  273.  
  274.     if (!mSource.pSharedObject && mSource.pixmap.w == info.pixmap.w && mSource.pixmap.h == info.pixmap.h && mSource.pixmap.format == info.pixmap.format) {
  275.         mSource = info;
  276.         return true;
  277.     }
  278.  
  279.     return false;
  280. }
  281.  
  282. bool VDVideoDisplayMinidriverGDI::Update(UpdateMode mode) {
  283.     if (!mSource.pixmap.data)
  284.         return false;
  285.  
  286.     if (!mSource.pSharedObject) {
  287.         GdiFlush();
  288.  
  289.         VDPixmap source(mSource.pixmap);
  290.  
  291.         char *dst = (char *)mpBitmapBits + mPitch*(source.h - 1);
  292.         ptrdiff_t dstpitch = -mPitch;
  293.  
  294.         if (mSource.bInterlaced && (mode & kModeFieldMask) != kModeAllFields) {
  295.             if ((mode & kModeFieldMask) == kModeOddField) {
  296.                 source.data = (char *)source.data + source.pitch;
  297.                 source.h >>= 1;
  298.                 dst += dstpitch;
  299.             } else {
  300.                 source.h = (source.h + 1) >> 1;
  301.             }
  302.  
  303.             source.pitch += source.pitch;
  304.             dstpitch += dstpitch;
  305.         }
  306.  
  307.         VDPixmap dstbm = { dst, NULL, source.w, source.h, dstpitch, source.format };
  308.  
  309.         if (mbPaletted) {
  310.             dstbm.format = nsVDPixmap::kPixFormat_Pal8;
  311.  
  312.             VDDitherImage(dstbm, source, mIdentTab);
  313.         } else {
  314.             switch(source.format) {
  315.             case nsVDPixmap::kPixFormat_YUV422_UYVY:
  316.             case nsVDPixmap::kPixFormat_YUV422_YUYV:
  317.             case nsVDPixmap::kPixFormat_YUV444_Planar:
  318.             case nsVDPixmap::kPixFormat_YUV422_Planar:
  319.             case nsVDPixmap::kPixFormat_YUV420_Planar:
  320.             case nsVDPixmap::kPixFormat_YUV411_Planar:
  321.             case nsVDPixmap::kPixFormat_YUV410_Planar:
  322.             case nsVDPixmap::kPixFormat_Y8:
  323.             case nsVDPixmap::kPixFormat_YUV422_V210:
  324.             case nsVDPixmap::kPixFormat_YUV422_UYVY_709:
  325.             case nsVDPixmap::kPixFormat_YUV420_NV12:
  326.                 dstbm.format = mScreenFormat;
  327.                 break;
  328.             }
  329.  
  330.             VDPixmapBlt(dstbm, source);
  331.         }
  332.  
  333.         if (mbDisplayDebugInfo) {
  334.             int saveIndex = SaveDC(mhdc);
  335.             if (saveIndex) {
  336.                 SetTextColor(mhdc, RGB(255, 255, 0));
  337.                 SetBkColor(mhdc, RGB(0, 0, 0));
  338.                 SetBkMode(mhdc, OPAQUE);
  339.                 SetTextAlign(mhdc, TA_BOTTOM | TA_LEFT);
  340.                 SelectObject(mhdc, GetStockObject(DEFAULT_GUI_FONT));
  341.  
  342.                 VDStringA desc;
  343.                 GetFormatString(mSource, desc);
  344.                 VDStringA s;
  345.                 s.sprintf("GDI minidriver - %s", desc.c_str());
  346.  
  347.                 TextOut(mhdc, 10, source.h - 10, s.data(), s.size());
  348.                 RestoreDC(mhdc, saveIndex);
  349.             }
  350.         }
  351.  
  352.         mbValid = true;
  353.     }
  354.  
  355.     return true;
  356. }
  357.  
  358. void VDVideoDisplayMinidriverGDI::Refresh(UpdateMode mode) {
  359.     if (mbValid) {
  360.         if (HDC hdc = GetDC(mhwnd)) {
  361.             RECT r;
  362.  
  363.             GetClientRect(mhwnd, &r);
  364.             InternalRefresh(hdc, r, mode);
  365.             ReleaseDC(mhwnd, hdc);
  366.         }
  367.     }
  368. }
  369.  
  370. bool VDVideoDisplayMinidriverGDI::Paint(HDC hdc, const RECT& rClient, UpdateMode mode) {
  371.     InternalRefresh(hdc, rClient, mode);
  372.     return true;
  373. }
  374.  
  375. bool VDVideoDisplayMinidriverGDI::SetSubrect(const vdrect32 *r) {
  376.     if (r) {
  377.         mbUseSubrect = true;
  378.         mSubrect = *r;
  379.     } else
  380.         mbUseSubrect = false;
  381.  
  382.     return true;
  383. }
  384.  
  385. void VDVideoDisplayMinidriverGDI::InternalRefresh(HDC hdc, const RECT& rClient, UpdateMode mode) {
  386.     if (rClient.right <= 0 || rClient.bottom <= 0)
  387.         return;
  388.  
  389.     SetStretchBltMode(hdc, COLORONCOLOR);
  390.  
  391.     const VDPixmap& source = mSource.pixmap;
  392.  
  393.     vdrect32 r;
  394.     if (mbUseSubrect)
  395.         r = mSubrect;
  396.     else
  397.         r.set(0, 0, source.w, source.h);
  398.  
  399.     if (mColorOverride) {
  400.         SetBkColor(hdc, VDSwizzleU32(mColorOverride) >> 8);
  401.         SetBkMode(hdc, OPAQUE);
  402.         ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rClient, "", 0, NULL);
  403.         return;
  404.     }
  405.  
  406.     if (mSource.bInterlaced) {
  407.         int fieldMode = mode & kModeFieldMask;
  408.         uint32 vinc        = (r.height() << 16) / rClient.bottom;
  409.         uint32 vaccum    = (vinc >> 1) + (r.top << 16);
  410.         uint32 vtlimit    = (((r.height() + 1) >> 1) << 17) - 1;
  411.         int fieldbase    = (fieldMode == kModeOddField ? 1 : 0);
  412.         int ystep        = (fieldMode == kModeAllFields) ? 1 : 2;
  413.  
  414.         vaccum += vinc*fieldbase;
  415.         vinc *= ystep;
  416.  
  417.         for(int y = fieldbase; y < rClient.bottom; y += ystep) {
  418.             int v;
  419.  
  420.             if (y & 1) {
  421.                 uint32 vt = vaccum < 0x8000 ? 0 : vaccum - 0x8000;
  422.  
  423.                 v = (y&1) + ((vt>>16) & ~1);
  424.             } else {
  425.                 uint32 vt = vaccum + 0x8000;
  426.  
  427.                 if (vt > vtlimit)
  428.                     vt = vtlimit;
  429.  
  430.                 v = (vt>>16) & ~1;
  431.             }
  432.  
  433.             StretchBlt(hdc, 0, y, rClient.right, 1, mhdc, r.left, v, r.width(), 1, SRCCOPY);
  434.             vaccum += vinc;
  435.         }
  436.     } else {
  437.         StretchBlt(hdc, 0, 0, rClient.right, rClient.bottom, mhdc, r.left, r.top, r.width(), r.height(), SRCCOPY);
  438.     }
  439. }
  440.  
  441. int VDVideoDisplayMinidriverGDI::GetScreenIntermediatePixmapFormat(HDC hdc) {
  442.     int pxformat = 0;
  443.  
  444.     // First, get the depth of the screen and guess that way.
  445.     int depth = GetDeviceCaps(hdc, BITSPIXEL);
  446.  
  447.     if (depth < 24)
  448.         pxformat = nsVDPixmap::kPixFormat_RGB565;
  449.     else if (depth < 32)
  450.         pxformat = nsVDPixmap::kPixFormat_RGB888;
  451.     else
  452.         pxformat = nsVDPixmap::kPixFormat_XRGB8888;
  453.  
  454.     // If the depth is 16-bit, attempt to determine the exact format.
  455.     if (HBITMAP hbm = CreateCompatibleBitmap(hdc, 1, 1)) {
  456.         struct {
  457.             BITMAPV5HEADER hdr;
  458.             RGBQUAD buf[256];
  459.         } format={0};
  460.  
  461.         if (GetDIBits(hdc, hbm, 0, 1, NULL, (LPBITMAPINFO)&format, DIB_RGB_COLORS)
  462.             && GetDIBits(hdc, hbm, 0, 1, NULL, (LPBITMAPINFO)&format, DIB_RGB_COLORS))
  463.         {
  464.             if (format.hdr.bV5Size >= sizeof(BITMAPINFOHEADER)) {
  465.                 const BITMAPV5HEADER& hdr = format.hdr;
  466.  
  467.                 if (hdr.bV5Planes == 1) {
  468.                     if (hdr.bV5Compression == BI_BITFIELDS) {
  469.                         if (hdr.bV5BitCount == 16 && hdr.bV5RedMask == 0x7c00 && hdr.bV5GreenMask == 0x03e0 && hdr.bV5BlueMask == 0x7c00)
  470.                             pxformat = nsVDPixmap::kPixFormat_XRGB1555;
  471.                         else if (hdr.bV5BitCount == 16 && hdr.bV5RedMask == 0xf800 && hdr.bV5GreenMask == 0x07e0 && hdr.bV5BlueMask == 0x7c00)
  472.                             pxformat = nsVDPixmap::kPixFormat_RGB565;
  473.                         else if (hdr.bV5BitCount == 24 && hdr.bV5RedMask == 0xff0000 && hdr.bV5GreenMask == 0x00ff00 && hdr.bV5BlueMask == 0x0000ff)
  474.                             pxformat = nsVDPixmap::kPixFormat_RGB888;
  475.                         else if (hdr.bV5BitCount == 32 && hdr.bV5RedMask == 0x00ff0000 && hdr.bV5GreenMask == 0x0000ff00 && hdr.bV5BlueMask == 0x000000ff)
  476.                             pxformat = nsVDPixmap::kPixFormat_XRGB8888;
  477.                     } else if (hdr.bV5Compression == BI_RGB) {
  478.                         if (hdr.bV5BitCount == 16)
  479.                             pxformat = nsVDPixmap::kPixFormat_XRGB1555;
  480.                         else if (hdr.bV5BitCount == 24)
  481.                             pxformat = nsVDPixmap::kPixFormat_RGB888;
  482.                         else if (hdr.bV5BitCount == 32)
  483.                             pxformat = nsVDPixmap::kPixFormat_XRGB8888;
  484.                     }
  485.                 }
  486.             }
  487.         }
  488.  
  489.         DeleteObject(hbm);
  490.     }
  491.  
  492.     return pxformat;
  493. }
  494.