Guest User

AviSynth Direct2D Rendering

a guest
Jan 10th, 2020
143
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. #define WIN32_LEAN_AND_MEAN
  3.  
  4. #include "targetver.h"
  5. #include <windows.h>
  6. #include "resource.h"
  7. #include "commctrl.h"
  8. #include <d2d1.h>
  9. #include <d2d1_1.h>
  10.  
  11. #include "avisynth_headers\avisynth.h"
  12.  
  13. HWND  g_MainWindow  = NULL;
  14. HWND  g_VideoWindow = NULL;
  15. HWND  g_Trackbar    = NULL;
  16.  
  17. HMODULE g_AvsDLL = NULL;
  18.  
  19. int   g_Position   = 0;
  20. int   g_BorderSize = 0;
  21.                    
  22. float g_DpiScale = 0;
  23.  
  24. const AVS_Linkage*  AVS_linkage = NULL;
  25. IScriptEnvironment* g_AvsScriptEnvironment = NULL;
  26. PClip               g_AvsClip;
  27. AVSValue            g_AvsValue;
  28. VideoInfo           g_AvsVideoInfo;
  29.  
  30. ID2D1Factory*          g_D2D_Factory   = NULL;
  31. ID2D1HwndRenderTarget* g_RenderTarget  = NULL;
  32. ID2D1DeviceContext*    g_DeviceContext = NULL;
  33.  
  34. HRESULT CreateGraphicsResources();
  35. void    DiscardGraphicsResources();
  36. void    OnPaint();
  37. void    ShowLastError();
  38.  
  39. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  40. template <class T> void SafeRelease(T** ppT);
  41.  
  42.  
  43. int APIENTRY wWinMain(
  44.     _In_     HINSTANCE hInstance,
  45.     _In_opt_ HINSTANCE hPrevInstance,
  46.     _In_     LPWSTR    lpCmdLine,
  47.     _In_     int       nCmdShow)
  48. {    
  49.     // D2D
  50.  
  51.     if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &g_D2D_Factory)))
  52.         throw;
  53.  
  54.     // AviSynth
  55.  
  56.     g_AvsDLL = LoadLibrary(L"AviSynth");
  57.  
  58.     if (!g_AvsDLL)
  59.         throw;
  60.  
  61.     IScriptEnvironment* (*CreateScriptEnvironment)(int version) =
  62.         (IScriptEnvironment * (*)(int)) GetProcAddress(g_AvsDLL, "CreateScriptEnvironment");
  63.  
  64.     if (!CreateScriptEnvironment)
  65.         throw;
  66.  
  67.     int avsInterfaceVersion = 6;
  68.     g_AvsScriptEnvironment = CreateScriptEnvironment(avsInterfaceVersion);
  69.  
  70.     if (!g_AvsScriptEnvironment)
  71.         throw;
  72.  
  73.     AVS_linkage = g_AvsScriptEnvironment->GetAVSLinkage();
  74.  
  75.     AVSValue src("D:\\Samples\\Mad Max - Fury Road_temp\\Mad Max - Fury Road_new.avs");
  76.  
  77.     g_AvsValue = g_AvsScriptEnvironment->Invoke("Import", AVSValue(&src, 1));
  78.     g_AvsValue = g_AvsScriptEnvironment->Invoke("ConvertToRGB32", g_AvsValue);
  79.     g_AvsValue = g_AvsScriptEnvironment->Invoke("FlipVertical", g_AvsValue);
  80.  
  81.     if (!g_AvsValue.IsClip())
  82.         throw;
  83.  
  84.     g_AvsClip      = g_AvsValue.AsClip();
  85.     g_AvsVideoInfo = g_AvsClip->GetVideoInfo();
  86.  
  87.     // main window class
  88.    
  89.     WNDCLASSEXW wcex;
  90.     ZeroMemory(&wcex, sizeof(wcex));
  91.     LPCWCHAR mainWindowClass  = L"AvsMainWindowClass";
  92.  
  93.     wcex.cbSize = sizeof(WNDCLASSEX);
  94.     wcex.style = CS_HREDRAW | CS_VREDRAW;
  95.     wcex.lpfnWndProc = WndProc;
  96.     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  97.     wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_MAIN);
  98.     wcex.lpszClassName = mainWindowClass;
  99.     wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  100.  
  101.     if (!RegisterClassEx(&wcex))
  102.     {
  103.         ShowLastError();
  104.         throw;
  105.     }
  106.  
  107.     // video window class
  108.  
  109.     ZeroMemory(&wcex, sizeof(wcex));
  110.     LPCWCHAR videoWindowClass = L"AvsVideoWindowClass";
  111.  
  112.     wcex.cbSize = sizeof(WNDCLASSEX);
  113.     wcex.style = CS_HREDRAW | CS_VREDRAW;
  114.     wcex.lpfnWndProc = WndProc;
  115.     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  116.     wcex.lpszClassName = videoWindowClass;
  117.  
  118.     if (!RegisterClassEx(&wcex))
  119.     {
  120.         ShowLastError();
  121.         throw;
  122.     }
  123.  
  124.     // create and setup window and controls
  125.  
  126.     HDC screen = GetDC(NULL);
  127.     g_DpiScale = GetDeviceCaps(screen, LOGPIXELSX) / (float)96;
  128.     ReleaseDC(NULL, screen);
  129.  
  130.     g_BorderSize = (int)(10 * g_DpiScale);
  131.  
  132.     g_MainWindow = CreateWindowEx(
  133.         NULL, mainWindowClass, L"AviSynth Direct2D Rendering", WS_OVERLAPPEDWINDOW,
  134.         CW_USEDEFAULT, CW_USEDEFAULT,
  135.         (int)(650 * g_DpiScale), (int)(500 * g_DpiScale),
  136.         NULL, NULL, hInstance, NULL);
  137.  
  138.     RECT clientRect;
  139.     GetClientRect(g_MainWindow, &clientRect);
  140.  
  141.     g_VideoWindow = CreateWindowEx(
  142.         NULL, videoWindowClass, NULL, WS_CHILD | WS_VISIBLE,
  143.         g_BorderSize, g_BorderSize,
  144.         clientRect.right - g_BorderSize * 2,
  145.         clientRect.bottom - g_BorderSize * 6,
  146.         g_MainWindow, NULL, hInstance, NULL);
  147.  
  148.     g_Trackbar = CreateWindowEx(
  149.         NULL, TRACKBAR_CLASS, NULL, WS_CHILD | WS_VISIBLE,
  150.         g_BorderSize, clientRect.bottom - g_BorderSize * 4,
  151.         clientRect.right - g_BorderSize * 2, g_BorderSize * 3,
  152.         g_MainWindow, NULL, hInstance, NULL);
  153.  
  154.     int max = g_AvsVideoInfo.num_frames - 1;
  155.     SendMessage(g_Trackbar, TBM_SETRANGE, TRUE, MAKELONG(0, max));
  156.     SetFocus(g_Trackbar);
  157.     ShowWindow(g_MainWindow, nCmdShow);
  158.     UpdateWindow(g_MainWindow);
  159.  
  160.     // message handling
  161.  
  162.     HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MAIN));
  163.     MSG msg;
  164.  
  165.     while (GetMessage(&msg, NULL, 0, 0))
  166.     {
  167.         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
  168.         {
  169.             TranslateMessage(&msg);
  170.             DispatchMessage(&msg);
  171.         }
  172.     }
  173.  
  174.     return (int) msg.wParam;
  175. }
  176.  
  177.  
  178. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  179. {
  180.     switch (message)
  181.     {
  182.     case WM_COMMAND:
  183.         switch (LOWORD(wParam))
  184.         {
  185.         case IDM_EXIT:
  186.             DestroyWindow(hWnd);
  187.             break;
  188.  
  189.         default:
  190.             return DefWindowProc(hWnd, message, wParam, lParam);
  191.         }
  192.  
  193.         break;
  194.  
  195.     case WM_PAINT:
  196.         OnPaint();
  197.         return 0;
  198.  
  199.     case WM_DESTROY:
  200.         DiscardGraphicsResources();
  201.         SafeRelease(&g_D2D_Factory);
  202.  
  203.         g_AvsClip = NULL;
  204.         g_AvsValue = NULL;
  205.         AVS_linkage = NULL;
  206.  
  207.         if (g_AvsScriptEnvironment)
  208.         {
  209.             g_AvsScriptEnvironment->DeleteScriptEnvironment();
  210.             g_AvsScriptEnvironment = NULL;
  211.         }
  212.  
  213.         FreeLibrary(g_AvsDLL);
  214.         PostQuitMessage(0);
  215.         return 0;
  216.  
  217.     case WM_SIZE:
  218.     {
  219.         RECT clientRect;
  220.         GetClientRect(g_MainWindow, &clientRect);
  221.  
  222.         MoveWindow(g_VideoWindow,
  223.             g_BorderSize, g_BorderSize,
  224.             clientRect.right - g_BorderSize * 2,
  225.             clientRect.bottom - g_BorderSize * 6,
  226.             FALSE
  227.         );
  228.  
  229.         MoveWindow(g_Trackbar,
  230.             g_BorderSize, clientRect.bottom - g_BorderSize * 4,
  231.             clientRect.right - g_BorderSize * 2, g_BorderSize * 3,
  232.             FALSE);
  233.  
  234.         if (g_RenderTarget != NULL)
  235.         {
  236.             RECT rect;
  237.             GetClientRect(g_VideoWindow, &rect);
  238.             D2D1_SIZE_U size = D2D1::SizeU(rect.right, rect.bottom);
  239.             g_RenderTarget->Resize(size);
  240.             InvalidateRect(g_VideoWindow, NULL, FALSE);
  241.         }
  242.  
  243.         return 0;
  244.     }
  245.  
  246.     case WM_HSCROLL:
  247.         if ((HWND)lParam == g_Trackbar)
  248.         {
  249.             if (!HIWORD(wParam))
  250.                 g_Position = (int)SendMessage(g_Trackbar, TBM_GETPOS, 0, 0);
  251.             else if (LOWORD(wParam) == TB_THUMBPOSITION || LOWORD(wParam) == TB_THUMBTRACK)
  252.                 g_Position = HIWORD(wParam);
  253.  
  254.             InvalidateRect(g_VideoWindow, NULL, FALSE);
  255.             return 0;
  256.         }
  257.  
  258.     default:
  259.         return DefWindowProc(hWnd, message, wParam, lParam);
  260.     }
  261.  
  262.     return 0;
  263. }
  264.  
  265.  
  266. template <class T> void SafeRelease(T** ppT)
  267. {
  268.     if (*ppT)
  269.     {
  270.         (*ppT)->Release();
  271.         *ppT = NULL;
  272.     }
  273. }
  274.  
  275.  
  276. HRESULT CreateGraphicsResources()
  277. {
  278.     HRESULT hr = S_OK;
  279.  
  280.     if (g_RenderTarget == NULL)
  281.     {
  282.         RECT rect;
  283.         GetClientRect(g_VideoWindow, &rect);
  284.         D2D1_SIZE_U size = D2D1::SizeU(rect.right, rect.bottom);
  285.  
  286.         hr = g_D2D_Factory->CreateHwndRenderTarget(
  287.             D2D1::RenderTargetProperties(),
  288.             D2D1::HwndRenderTargetProperties(g_VideoWindow, size),
  289.             &g_RenderTarget);
  290.  
  291.         if (SUCCEEDED(hr))
  292.         {
  293.             hr = g_RenderTarget->QueryInterface(
  294.                 __uuidof(ID2D1DeviceContext),
  295.                 reinterpret_cast<void**>(&g_DeviceContext)
  296.             );
  297.         }
  298.     }
  299.  
  300.     return hr;
  301. }
  302.  
  303.  
  304. void DiscardGraphicsResources()
  305. {    
  306.     SafeRelease(&g_DeviceContext);
  307.     SafeRelease(&g_RenderTarget);
  308. }
  309.  
  310.  
  311. void OnPaint()
  312. {
  313.     HRESULT hr = CreateGraphicsResources();
  314.  
  315.     if (SUCCEEDED(hr))
  316.     {
  317.         g_DeviceContext->BeginDraw();
  318.  
  319.         PVideoFrame frame = g_AvsClip->GetFrame(g_Position, g_AvsScriptEnvironment);
  320.         auto pixelData = frame->GetReadPtr();
  321.  
  322.         if (pixelData)
  323.         {
  324.             D2D1_BITMAP_PROPERTIES properties;
  325.             properties.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE);
  326.             properties.dpiX = properties.dpiY = 96;
  327.             ID2D1Bitmap* pBitmap = NULL;
  328.             D2D1_SIZE_U size = D2D1::SizeU(g_AvsVideoInfo.width, g_AvsVideoInfo.height);
  329.             hr = g_DeviceContext->CreateBitmap(size, pixelData, frame->GetPitch(), properties, &pBitmap);
  330.  
  331.             if (SUCCEEDED(hr))
  332.             {
  333.                 D2D1_SIZE_F sizeDestination = g_DeviceContext->GetSize();
  334.                 D2D1_RECT_F rectDestination = D2D1::RectF(0, 0, sizeDestination.width, sizeDestination.height);
  335.                 g_DeviceContext->DrawBitmap(pBitmap, &rectDestination, 1.0, D2D1_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC);
  336.                 pBitmap->Release();
  337.             }
  338.         }
  339.  
  340.         hr = g_DeviceContext->EndDraw();
  341.  
  342.         if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
  343.             DiscardGraphicsResources();
  344.     }
  345. }
  346.  
  347.  
  348. void ShowLastError()
  349. {
  350.     DWORD  errorCode = GetLastError();
  351.     LPWSTR errorText = NULL;
  352.  
  353.     FormatMessage(
  354.         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, errorCode,
  355.         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&errorText, 0, NULL);
  356.  
  357.     if (errorText)
  358.     {
  359.         MessageBox(g_MainWindow, errorText, NULL, NULL);
  360.         LocalFree(errorText);
  361.     }
  362. }
RAW Paste Data