[vlc-devel] [PATCH 5/8] doc: add a sample app to test the Direct3D9 host of libvlc
Steve Lhomme
robux4 at ycbcr.xyz
Mon Jan 21 17:38:48 CET 2019
---
doc/libvlc/d3d9_player.c | 315 +++++++++++++++++++++++++++++++++++++++
1 file changed, 315 insertions(+)
create mode 100644 doc/libvlc/d3d9_player.c
diff --git a/doc/libvlc/d3d9_player.c b/doc/libvlc/d3d9_player.c
new file mode 100644
index 0000000000..bd93253f99
--- /dev/null
+++ b/doc/libvlc/d3d9_player.c
@@ -0,0 +1,315 @@
+/* compile using: gcc d3d9_player.c -o d3d9_player.exe -I <path/liblc> -llibvlc -ld3d9 */
+
+#include <windows.h>
+#include <windowsx.h>
+#define COBJMACROS
+#include <d3d9.h>
+
+#include <vlc/vlc.h>
+
+struct render_context
+{
+ HWND hWnd;
+
+ IDirect3D9 *d3d;
+ IDirect3DDevice9 *d3ddev;
+
+ /* surface that VLC will render to */
+ IDirect3DSurface9 *renderSurface;
+
+ /* our swapchain backbuffer */
+ IDirect3DSurface9 *backBuffer;
+
+ IDirect3DVertexBuffer9 *rectangleVertexBuf;
+};
+
+struct CUSTOMVERTEX {FLOAT X, Y, Z, RHW; DWORD COLOR;
+ FLOAT tu, tv; /* texture relative coordinates */};
+#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
+
+/**
+ * Callback called just before VLC starts drawing the video.
+ *
+ * Set the surface VLC will render to (could be the backbuffer if nothing else
+ * needs to be displayed). And then call BeginScene().
+ *
+ * This is called outside of the UI thread (in the VLC rendering thread).
+ */
+static bool StartRender(struct render_context *ctx)
+{
+ HRESULT hr;
+
+ hr = IDirect3DDevice9_SetRenderTarget(ctx->d3ddev, 0, ctx->renderSurface);
+ if (FAILED(hr)) return false;
+
+ /* clear the vlc destination texture to black alternatively */
+ hr = IDirect3DDevice9_Clear(ctx->d3ddev, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
+ if (FAILED(hr)) return false;
+
+ hr = IDirect3DDevice9_BeginScene(ctx->d3ddev);
+ if (hr == D3DERR_DEVICENOTRESET)
+ {
+ /* TODO reset the device, this may not work with hardware decoding */
+ return false;
+ }
+ if (FAILED(hr)) return false;
+
+ return true;
+}
+
+/**
+ * Callback called after VLC has finished drawing the video.
+ *
+ * This is called outside of the UI thread (in the VLC rendering thread).
+ */
+static void EndRender(struct render_context *ctx)
+{
+ IDirect3DDevice9_EndScene(ctx->d3ddev);
+}
+
+/**
+ * Callback called when it's time to display the video, in sync with the audio.
+ *
+ * This is called outside of the UI thread (in the VLC rendering thread).
+ */
+static void Swap(struct render_context *ctx)
+{
+ /* finished drawing to our swap surface, now render that surface to the backbuffer */
+ IDirect3DDevice9_SetRenderTarget(ctx->d3ddev, 0, ctx->backBuffer);
+
+ /* clear the backbuffer to orange */
+ IDirect3DDevice9_Clear(ctx->d3ddev, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 120, 0), 1.0f, 0);
+
+ IDirect3DDevice9_BeginScene(ctx->d3ddev);
+ IDirect3DDevice9_SetStreamSource(ctx->d3ddev, 0, ctx->rectangleVertexBuf, 0, sizeof(struct CUSTOMVERTEX));
+ IDirect3DDevice9_SetFVF(ctx->d3ddev, CUSTOMFVF);
+ IDirect3DDevice9_DrawPrimitive(ctx->d3ddev, D3DPT_TRIANGLEFAN, 0, 2);
+ IDirect3DDevice9_EndScene(ctx->d3ddev);
+
+ IDirect3DDevice9_Present(ctx->d3ddev, NULL, NULL, ctx->hWnd, NULL);
+}
+
+/**
+ * Callback called to tell the size of the surface that should be available
+ * to VLC to draw into.
+ *
+ * This is called outside of the UI thread (not the VLC rendering thread).
+ */
+static bool Resize(struct render_context *ctx, unsigned width, unsigned height)
+{
+ HRESULT hr;
+ D3DDISPLAYMODE d3ddm;
+
+ hr = IDirect3D9_GetAdapterDisplayMode(ctx->d3d, 0, &d3ddm);
+
+ /* create the output surface VLC will write to */
+ if (ctx->renderSurface)
+ {
+ IDirect3DSurface9_Release(ctx->renderSurface);
+ ctx->renderSurface = NULL;
+ }
+ hr = IDirect3DDevice9_CreateRenderTarget(ctx->d3ddev,
+ width, height,
+ d3ddm.Format,
+ D3DMULTISAMPLE_NONE,
+ 0,
+ FALSE,
+ &ctx->renderSurface,
+ NULL);
+ if (FAILED(hr))
+ return false;
+ return true;
+}
+
+static void init_direct3d(struct render_context *ctx, HWND hWnd)
+{
+ ctx->hWnd = hWnd;
+ ctx->d3d = Direct3DCreate9(D3D_SDK_VERSION);
+
+ D3DPRESENT_PARAMETERS d3dpp = { 0 };
+ d3dpp.Windowed = TRUE;
+ d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ d3dpp.hDeviceWindow = hWnd;
+
+ IDirect3D9_CreateDevice(ctx->d3d, D3DADAPTER_DEFAULT,
+ D3DDEVTYPE_HAL,
+ NULL,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING,
+ &d3dpp,
+ &ctx->d3ddev);
+
+ IDirect3DDevice9_GetRenderTarget(ctx->d3ddev, 0, &ctx->backBuffer);
+
+
+ struct CUSTOMVERTEX rectangleVertices[] =
+ {
+ { 20.0f, 10.0f, 0.0f, 1.0f, D3DCOLOR_ARGB(255, 255, 255, 255), 0.0f, 0.0f },
+ { 650.0f, 10.0f, 0.0f, 1.0f, D3DCOLOR_ARGB(255, 255, 255, 255), 1.0f, 0.0f },
+ { 650.0f, 500.0f, 0.0f, 1.0f, D3DCOLOR_ARGB(255, 255, 255, 255), 1.0f, 1.0f },
+ { 20.0f, 500.0f, 0.0f, 1.0f, D3DCOLOR_ARGB(255, 255, 255, 255), 0.0f, 1.0f },
+ };
+ IDirect3DDevice9_CreateVertexBuffer(ctx->d3ddev, sizeof(rectangleVertices),
+ 0,
+ CUSTOMFVF,
+ D3DPOOL_MANAGED,
+ &ctx->rectangleVertexBuf,
+ NULL);
+
+ LPVOID pVoid;
+ IDirect3DVertexBuffer9_Lock(ctx->rectangleVertexBuf, 0, 0, (void**)&pVoid, 0);
+ memcpy(pVoid, rectangleVertices, sizeof(rectangleVertices));
+ IDirect3DVertexBuffer9_Unlock(ctx->rectangleVertexBuf);
+}
+
+static void release_direct3d(struct render_context *ctx)
+{
+ if (ctx->backBuffer)
+ IDirect3DSurface9_Release(ctx->backBuffer);
+ if (ctx->renderSurface)
+ IDirect3DSurface9_Release(ctx->renderSurface);
+ if (ctx->rectangleVertexBuf)
+ IDirect3DVertexBuffer9_Release(ctx->rectangleVertexBuf);
+ IDirect3DDevice9_Release(ctx->d3ddev);
+ IDirect3D9_Release(ctx->d3d);
+}
+
+static int VideoControl(void* opaque, libvlc_video_callback_control_t control,
+ const void *input, void **output)
+{
+ struct render_context *ctx = opaque;
+
+ switch (control)
+ {
+ case LIBVLC_VIDEO_SETUP:
+ *output = ctx->d3ddev;
+ break;
+ case LIBVLC_VIDEO_CLEANUP:
+ /* here we can release all things Direct3D9 for good (if playing only one file) */
+ break;
+ case LIBVLC_VIDEO_UPDATE_OUTPUT:
+ {
+ const libvlc_video_callback_cfg_t *cfg = input;
+ if (!Resize(ctx, cfg->width, cfg->height))
+ return -1;
+ }
+ break;
+ case LIBVLC_VIDEO_SWAP:
+ Swap(ctx);
+ break;
+ case LIBVLC_VIDEO_START_RENDER:
+ if (!StartRender(ctx))
+ return -1;
+ break;
+ case LIBVLC_VIDEO_FINISHED_RENDERING:
+ EndRender(ctx);
+ break;
+ case LIBVLC_VIDEO_MAKE_CURRENT:
+ case LIBVLC_VIDEO_GET_PROCADDRESS:
+ /* ignore OpenGL specific controls */
+ break;
+ }
+ return 0;
+}
+
+static LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+ case WM_DESTROY:
+ {
+ PostQuitMessage(0);
+ return 0;
+ } break;
+ }
+
+ return DefWindowProc (hWnd, message, wParam, lParam);
+}
+
+int WINAPI WinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ HWND hWnd;
+ WNDCLASSEX wc;
+ struct render_context Context = { 0 };
+ char *file_path;
+ libvlc_instance_t *p_libvlc;
+ libvlc_media_t *p_media;
+ libvlc_media_player_t *p_mp;
+ (void)hPrevInstance;
+
+ ZeroMemory(&wc, sizeof(WNDCLASSEX));
+
+ wc.cbSize = sizeof(WNDCLASSEX);
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = WindowProc;
+ wc.hInstance = hInstance;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
+ wc.lpszClassName = "WindowClass";
+
+ RegisterClassEx(&wc);
+
+ hWnd = CreateWindowEx(0,
+ "WindowClass",
+ "libvlc Demo app",
+ WS_OVERLAPPEDWINDOW,
+ 300, 300,
+ 1070, 600,
+ NULL,
+ NULL,
+ hInstance,
+ NULL);
+
+ ShowWindow(hWnd, nCmdShow);
+
+ init_direct3d(&Context, hWnd);
+
+ /* remove "" around the given path */
+ if (lpCmdLine[0] == '"')
+ {
+ file_path = strdup( lpCmdLine+1 );
+ if (file_path[strlen(file_path)-1] == '"')
+ file_path[strlen(file_path)-1] = '\0';
+ }
+ else
+ file_path = strdup( lpCmdLine );
+
+ p_libvlc = libvlc_new( 0, NULL );
+ p_media = libvlc_media_new_path( p_libvlc, file_path );
+ free( file_path );
+ p_mp = libvlc_media_player_new_from_media( p_media );
+
+ // DON'T use with callbacks libvlc_media_player_set_hwnd(p_mp, hWnd);
+
+ /* Tell VLC to render into our D3D9 environment */
+ libvlc_video_set_surface_callbacks( p_mp, libvlc_video_engine_direct3d9,
+ VideoControl, &Context );
+
+ libvlc_media_player_play( p_mp );
+
+ MSG msg;
+
+ while(TRUE)
+ {
+ while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ if(msg.message == WM_QUIT)
+ break;
+ }
+
+ libvlc_media_player_stop( p_mp );
+
+ libvlc_media_player_release( p_mp );
+ libvlc_media_release( p_media );
+ libvlc_release( p_libvlc );
+
+ release_direct3d(&Context);
+
+ return msg.wParam;
+}
--
2.17.1
More information about the vlc-devel
mailing list