audiotrack: refactor
[vlc.git] / doc / libvlc / d3d11_player.cpp
blob2cac37a36e065953b95808483e07dc7a75a390c7
1 /* compile: g++ d3d11_player.cpp -o d3d11_player.exe -L<path/libvlc> -lvlc -ld3d11 -ld3dcompiler_47 -luuid */
3 /* This is the most extreme use case where libvlc is given its own ID3D11DeviceContext
4 and draws in a texture shared with the ID3D11DeviceContext of the app.
6 It's possible to share the ID3D11DeviceContext as long as the proper PixelShader
7 calls are overridden in the app after each libvlc drawing (see libvlc D3D11 doc).
9 It's also possible to use the SwapChain directly with libvlc and let it draw on its
10 entire area instead of drawing in a texture.
13 #include <windows.h>
14 #include <d3d11.h>
15 #include <d3dcompiler.h>
16 #include <assert.h>
18 #include <d3d11_1.h>
19 #include <dxgi1_2.h>
21 #ifdef DEBUG_D3D11_LEAKS
22 # include <initguid.h>
23 # include <dxgidebug.h>
24 #endif
26 #include <vlc/vlc.h>
28 #define SCREEN_WIDTH 1500
29 #define SCREEN_HEIGHT 900
30 #define BORDER_LEFT (-0.95f)
31 #define BORDER_RIGHT ( 0.85f)
32 #define BORDER_TOP ( 0.95f)
33 #define BORDER_BOTTOM (-0.90f)
35 #define check_leak(x) assert(x)
37 struct render_context
39 HWND hWnd;
41 libvlc_media_player_t *p_mp;
43 /* resources shared by VLC */
44 ID3D11Device *d3deviceVLC;
45 ID3D11DeviceContext *d3dctxVLC;
47 struct {
48 ID3D11Texture2D *textureVLC; // shared between VLC and the app
49 ID3D11RenderTargetView *textureRenderTarget;
50 HANDLE sharedHandled; // handle of the texture used by VLC and the app
52 /* texture VLC renders into */
53 ID3D11Texture2D *texture;
54 ID3D11ShaderResourceView *textureShaderInput;
55 } resized;
57 /* Direct3D11 device/context */
58 ID3D11Device *d3device;
59 ID3D11DeviceContext *d3dctx;
61 IDXGISwapChain *swapchain;
62 ID3D11RenderTargetView *swapchainRenderTarget;
64 /* our vertex/pixel shader */
65 ID3D11VertexShader *pVS;
66 ID3D11PixelShader *pPS;
67 ID3D11InputLayout *pShadersInputLayout;
69 UINT vertexBufferStride;
70 ID3D11Buffer *pVertexBuffer;
72 UINT quadIndexCount;
73 ID3D11Buffer *pIndexBuffer;
75 ID3D11SamplerState *samplerState;
77 CRITICAL_SECTION sizeLock; // the ReportSize callback cannot be called during/after the Cleanup_cb is called
78 unsigned width, height;
79 void (*ReportSize)(void *ReportOpaque, unsigned width, unsigned height);
80 void *ReportOpaque;
83 static const char *shaderStr = "\
84 Texture2D shaderTexture;\n\
85 SamplerState samplerState;\n\
86 struct PS_INPUT\n\
87 {\n\
88 float4 position : SV_POSITION;\n\
89 float4 textureCoord : TEXCOORD0;\n\
90 };\n\
91 \n\
92 float4 PShader(PS_INPUT In) : SV_TARGET\n\
93 {\n\
94 return shaderTexture.Sample(samplerState, In.textureCoord);\n\
95 }\n\
96 \n\
97 struct VS_INPUT\n\
98 {\n\
99 float4 position : POSITION;\n\
100 float4 textureCoord : TEXCOORD0;\n\
101 };\n\
103 struct VS_OUTPUT\n\
104 {\n\
105 float4 position : SV_POSITION;\n\
106 float4 textureCoord : TEXCOORD0;\n\
107 };\n\
109 VS_OUTPUT VShader(VS_INPUT In)\n\
110 {\n\
111 return In;\n\
112 }\n\
115 struct SHADER_INPUT {
116 struct {
117 FLOAT x;
118 FLOAT y;
119 FLOAT z;
120 } position;
121 struct {
122 FLOAT x;
123 FLOAT y;
124 } texture;
127 static void init_direct3d(struct render_context *ctx)
129 HRESULT hr;
130 DXGI_SWAP_CHAIN_DESC scd = { };
132 scd.BufferCount = 1;
133 scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
134 scd.BufferDesc.Width = SCREEN_WIDTH;
135 scd.BufferDesc.Height = SCREEN_HEIGHT;
136 scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
137 scd.OutputWindow = ctx->hWnd;
138 scd.SampleDesc.Count = 1;
139 scd.Windowed = TRUE;
140 scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
142 UINT creationFlags = 0;
143 #ifndef NDEBUG
144 creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
145 #endif
147 D3D11CreateDeviceAndSwapChain(NULL,
148 D3D_DRIVER_TYPE_HARDWARE,
149 NULL,
150 creationFlags,
151 NULL,
152 NULL,
153 D3D11_SDK_VERSION,
154 &scd,
155 &ctx->swapchain,
156 &ctx->d3device,
157 NULL,
158 &ctx->d3dctx);
160 /* The ID3D11Device must have multithread protection */
161 ID3D10Multithread *pMultithread;
162 hr = ctx->d3device->QueryInterface( __uuidof(ID3D10Multithread), (void **)&pMultithread);
163 if (SUCCEEDED(hr)) {
164 pMultithread->SetMultithreadProtected(TRUE);
165 pMultithread->Release();
168 // RECT currentRect;
169 // GetWindowRect(hWnd, &currentRect);
170 //currentRect.right - currentRect.left;
171 //currentRect.bottom - currentRect.top;
173 D3D11_VIEWPORT viewport = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0 };
175 ctx->d3dctx->RSSetViewports(1, &viewport);
177 D3D11CreateDevice(NULL,
178 D3D_DRIVER_TYPE_HARDWARE,
179 NULL,
180 creationFlags | D3D11_CREATE_DEVICE_VIDEO_SUPPORT, /* needed for hardware decoding */
181 NULL, 0,
182 D3D11_SDK_VERSION,
183 &ctx->d3deviceVLC, NULL, &ctx->d3dctxVLC);
185 ID3D11Texture2D *pBackBuffer;
186 ctx->swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
188 ctx->d3device->CreateRenderTargetView(pBackBuffer, NULL, &ctx->swapchainRenderTarget);
189 pBackBuffer->Release();
191 ctx->d3dctx->OMSetRenderTargets(1, &ctx->swapchainRenderTarget, NULL);
193 ID3D10Blob *VS, *PS, *pErrBlob;
194 char *err;
195 hr = D3DCompile(shaderStr, strlen(shaderStr),
196 NULL, NULL, NULL, "VShader", "vs_4_0", 0, 0, &VS, &pErrBlob);
197 err = pErrBlob ? (char*)pErrBlob->GetBufferPointer() : NULL;
198 hr = D3DCompile(shaderStr, strlen(shaderStr),
199 NULL, NULL, NULL, "PShader", "ps_4_0", 0, 0, &PS, &pErrBlob);
200 err = pErrBlob ? (char*)pErrBlob->GetBufferPointer() : NULL;
202 ctx->d3device->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &ctx->pVS);
203 ctx->d3device->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &ctx->pPS);
205 D3D11_INPUT_ELEMENT_DESC ied[] =
207 { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
208 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
211 hr = ctx->d3device->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &ctx->pShadersInputLayout);
212 SHADER_INPUT OurVertices[] =
214 {{BORDER_LEFT, BORDER_BOTTOM, 0.0f}, {0.0f, 1.0f}},
215 {{BORDER_RIGHT, BORDER_BOTTOM, 0.0f}, {1.0f, 1.0f}},
216 {{BORDER_RIGHT, BORDER_TOP, 0.0f}, {1.0f, 0.0f}},
217 {{BORDER_LEFT, BORDER_TOP, 0.0f}, {0.0f, 0.0f}},
220 D3D11_BUFFER_DESC bd;
221 ZeroMemory(&bd, sizeof(bd));
223 bd.Usage = D3D11_USAGE_DYNAMIC;
224 bd.ByteWidth = sizeof(OurVertices);
225 bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
226 bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
228 ctx->d3device->CreateBuffer(&bd, NULL, &ctx->pVertexBuffer);
229 ctx->vertexBufferStride = sizeof(OurVertices[0]);
231 D3D11_MAPPED_SUBRESOURCE ms;
232 ctx->d3dctx->Map(ctx->pVertexBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);
233 memcpy(ms.pData, OurVertices, sizeof(OurVertices));
234 ctx->d3dctx->Unmap(ctx->pVertexBuffer, NULL);
236 ctx->quadIndexCount = 6;
237 D3D11_BUFFER_DESC quadDesc = { };
238 quadDesc.Usage = D3D11_USAGE_DYNAMIC;
239 quadDesc.ByteWidth = sizeof(WORD) * ctx->quadIndexCount;
240 quadDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
241 quadDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
242 ctx->d3device->CreateBuffer(&quadDesc, NULL, &ctx->pIndexBuffer);
244 ctx->d3dctx->Map(ctx->pIndexBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);
245 WORD *triangle_pos = static_cast<WORD*>(ms.pData);
246 triangle_pos[0] = 3;
247 triangle_pos[1] = 1;
248 triangle_pos[2] = 0;
250 triangle_pos[3] = 2;
251 triangle_pos[4] = 1;
252 triangle_pos[5] = 3;
253 ctx->d3dctx->Unmap(ctx->pIndexBuffer, NULL);
255 ctx->d3dctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
257 ctx->d3dctx->IASetInputLayout(ctx->pShadersInputLayout);
258 UINT offset = 0;
259 ctx->d3dctx->IASetVertexBuffers(0, 1, &ctx->pVertexBuffer, &ctx->vertexBufferStride, &offset);
260 ctx->d3dctx->IASetIndexBuffer(ctx->pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
262 ctx->d3dctx->VSSetShader(ctx->pVS, 0, 0);
263 ctx->d3dctx->PSSetShader(ctx->pPS, 0, 0);
265 D3D11_SAMPLER_DESC sampDesc;
266 ZeroMemory(&sampDesc, sizeof(sampDesc));
267 sampDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
268 sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
269 sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
270 sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
271 sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
272 sampDesc.MinLOD = 0;
273 sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
275 hr = ctx->d3device->CreateSamplerState(&sampDesc, &ctx->samplerState);
276 ctx->d3dctx->PSSetSamplers(0, 1, &ctx->samplerState);
280 static void release_textures(struct render_context *ctx)
282 ULONG ref;
283 if (ctx->resized.sharedHandled)
285 CloseHandle(ctx->resized.sharedHandled);
286 ctx->resized.sharedHandled = NULL;
288 if (ctx->resized.textureVLC)
290 ref = ctx->resized.textureVLC->Release();
291 check_leak(ref == 0);
292 ctx->resized.textureVLC = NULL;
294 if (ctx->resized.textureShaderInput)
296 ref = ctx->resized.textureShaderInput->Release();
297 check_leak(ref == 0);
298 ctx->resized.textureShaderInput = NULL;
300 if (ctx->resized.textureRenderTarget)
302 ref = ctx->resized.textureRenderTarget->Release();
303 check_leak(ref == 0);
304 ctx->resized.textureRenderTarget = NULL;
306 if (ctx->resized.texture)
308 ref = ctx->resized.texture->Release();
309 check_leak(ref == 0);
310 ctx->resized.texture = NULL;
314 static void list_dxgi_leaks(void)
316 #ifdef DEBUG_D3D11_LEAKS
317 HMODULE dxgidebug_dll = LoadLibrary(TEXT("DXGIDEBUG.DLL"));
318 if (dxgidebug_dll)
320 typedef HRESULT (WINAPI * LPDXGIGETDEBUGINTERFACE)(REFIID, void ** );
321 LPDXGIGETDEBUGINTERFACE pf_DXGIGetDebugInterface;
322 pf_DXGIGetDebugInterface = reinterpret_cast<LPDXGIGETDEBUGINTERFACE>(
323 reinterpret_cast<void*>( GetProcAddress( dxgidebug_dll, "DXGIGetDebugInterface" ) ) );
324 if (pf_DXGIGetDebugInterface)
326 IDXGIDebug *pDXGIDebug;
327 if (SUCCEEDED(pf_DXGIGetDebugInterface(__uuidof(IDXGIDebug), (void**)&pDXGIDebug)))
328 pDXGIDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL);
329 pDXGIDebug->Release();
331 FreeLibrary(dxgidebug_dll);
333 #endif // DEBUG_D3D11_LEAKS
336 static void release_direct3d(struct render_context *ctx)
338 ULONG ref;
340 release_textures(ctx);
342 ref = ctx->d3dctxVLC->Release();
343 check_leak(ref == 0);
344 ref = ctx->d3deviceVLC->Release();
345 check_leak(ref == 0);
347 ref = ctx->samplerState->Release();
348 check_leak(ref == 0);
349 ref = ctx->pShadersInputLayout->Release();
350 check_leak(ref == 0);
351 ref = ctx->pVS->Release();
352 check_leak(ref == 0);
353 ref = ctx->pPS->Release();
354 check_leak(ref == 0);
355 ref = ctx->pIndexBuffer->Release();
356 check_leak(ref == 0);
357 ref = ctx->pVertexBuffer->Release();
358 check_leak(ref == 0);
359 ref = ctx->swapchain->Release();
360 check_leak(ref == 0);
361 ref = ctx->swapchainRenderTarget->Release();
362 check_leak(ref == 0);
363 ref = ctx->d3dctx->Release();
364 check_leak(ref == 0);
365 ref = ctx->d3device->Release();
366 check_leak(ref == 0);
368 list_dxgi_leaks();
371 static bool UpdateOutput_cb( void *opaque, const libvlc_video_render_cfg_t *cfg, libvlc_video_output_cfg_t *out )
373 struct render_context *ctx = static_cast<struct render_context *>( opaque );
375 HRESULT hr;
377 DXGI_FORMAT renderFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
379 release_textures(ctx);
381 /* interim texture */
382 D3D11_TEXTURE2D_DESC texDesc = { };
383 texDesc.MipLevels = 1;
384 texDesc.SampleDesc.Count = 1;
385 texDesc.MiscFlags = 0;
386 texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
387 texDesc.Usage = D3D11_USAGE_DEFAULT;
388 texDesc.CPUAccessFlags = 0;
389 texDesc.ArraySize = 1;
390 texDesc.Format = renderFormat;
391 texDesc.Height = cfg->height;
392 texDesc.Width = cfg->width;
393 texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED | D3D11_RESOURCE_MISC_SHARED_NTHANDLE;
395 hr = ctx->d3device->CreateTexture2D( &texDesc, NULL, &ctx->resized.texture );
396 if (FAILED(hr)) return false;
398 IDXGIResource1* sharedResource = NULL;
399 ctx->resized.texture->QueryInterface(__uuidof(IDXGIResource1), (LPVOID*) &sharedResource);
400 hr = sharedResource->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ|DXGI_SHARED_RESOURCE_WRITE, NULL, &ctx->resized.sharedHandled);
401 sharedResource->Release();
403 ID3D11Device1* d3d11VLC1;
404 ctx->d3deviceVLC->QueryInterface(__uuidof(ID3D11Device1), (LPVOID*) &d3d11VLC1);
405 hr = d3d11VLC1->OpenSharedResource1(ctx->resized.sharedHandled, __uuidof(ID3D11Texture2D), (void**)&ctx->resized.textureVLC);
406 d3d11VLC1->Release();
408 D3D11_SHADER_RESOURCE_VIEW_DESC resviewDesc;
409 ZeroMemory(&resviewDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
410 resviewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
411 resviewDesc.Texture2D.MipLevels = 1;
412 resviewDesc.Format = texDesc.Format;
413 hr = ctx->d3device->CreateShaderResourceView(ctx->resized.texture, &resviewDesc, &ctx->resized.textureShaderInput );
414 if (FAILED(hr)) return false;
416 ctx->d3dctx->PSSetShaderResources(0, 1, &ctx->resized.textureShaderInput);
418 D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc = {
419 .Format = texDesc.Format,
420 .ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D,
422 hr = ctx->d3deviceVLC->CreateRenderTargetView(ctx->resized.textureVLC, &renderTargetViewDesc, &ctx->resized.textureRenderTarget);
423 if (FAILED(hr)) return false;
425 ctx->d3dctxVLC->OMSetRenderTargets( 1, &ctx->resized.textureRenderTarget, NULL );
427 out->dxgi_format = renderFormat;
428 out->full_range = true;
429 out->colorspace = libvlc_video_colorspace_BT709;
430 out->primaries = libvlc_video_primaries_BT709;
431 out->transfer = libvlc_video_transfer_func_SRGB;
433 return true;
436 static void Swap_cb( void* opaque )
438 struct render_context *ctx = static_cast<struct render_context *>( opaque );
439 ctx->swapchain->Present( 0, 0 );
442 static bool StartRendering_cb( void *opaque, bool enter )
444 struct render_context *ctx = static_cast<struct render_context *>( opaque );
445 if ( enter )
447 // DEBUG: draw greenish background to show where libvlc doesn't draw in the texture
448 // Normally you should Clear with a black background
449 static const FLOAT greenRGBA[4] = {0.5f, 0.5f, 0.0f, 1.0f};
450 ctx->d3dctxVLC->ClearRenderTargetView( ctx->resized.textureRenderTarget, greenRGBA);
452 else
454 static const FLOAT orangeRGBA[4] = {1.0f, 0.5f, 0.0f, 1.0f};
455 ctx->d3dctx->ClearRenderTargetView(ctx->swapchainRenderTarget, orangeRGBA);
457 // Render into the swapchain
458 // We start the drawing of the shared texture in our app as early as possible
459 // in hope it's done as soon as Swap_cb is called
460 ctx->d3dctx->DrawIndexed(ctx->quadIndexCount, 0, 0);
463 return true;
466 static bool SelectPlane_cb( void *opaque, size_t plane )
468 struct render_context *ctx = static_cast<struct render_context *>( opaque );
469 if ( plane != 0 ) // we only support one packed RGBA plane (DXGI_FORMAT_R8G8B8A8_UNORM)
470 return false;
471 return true;
474 static bool Setup_cb( void **opaque, const libvlc_video_setup_device_cfg_t *cfg, libvlc_video_setup_device_info_t *out )
476 struct render_context *ctx = static_cast<struct render_context *>(*opaque);
478 init_direct3d(ctx);
480 out->d3d11.device_context = ctx->d3dctxVLC;
481 return true;
484 static void Cleanup_cb( void *opaque )
486 // here we can release all things Direct3D11 for good (if playing only one file)
487 struct render_context *ctx = static_cast<struct render_context *>( opaque );
488 release_direct3d(ctx);
491 static void Resize_cb( void *opaque,
492 void (*report_size_change)(void *report_opaque, unsigned width, unsigned height),
493 void *report_opaque )
495 struct render_context *ctx = static_cast<struct render_context *>( opaque );
496 EnterCriticalSection(&ctx->sizeLock);
497 ctx->ReportSize = report_size_change;
498 ctx->ReportOpaque = report_opaque;
500 if (ctx->ReportSize != nullptr)
502 /* report our initial size */
503 ctx->ReportSize(ctx->ReportOpaque, ctx->width, ctx->height);
505 LeaveCriticalSection(&ctx->sizeLock);
508 static const char *AspectRatio = NULL;
510 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
512 if( message == WM_CREATE )
514 /* Store p_mp for future use */
515 CREATESTRUCT *c = (CREATESTRUCT *)lParam;
516 SetWindowLongPtr( hWnd, GWLP_USERDATA, (LONG_PTR)c->lpCreateParams );
517 return 0;
520 LONG_PTR p_user_data = GetWindowLongPtr( hWnd, GWLP_USERDATA );
521 if( p_user_data == 0 )
522 return DefWindowProc(hWnd, message, wParam, lParam);
523 struct render_context *ctx = (struct render_context *)p_user_data;
525 switch(message)
527 case WM_SIZE:
529 /* tell libvlc that our size has changed */
530 ctx->width = LOWORD(lParam) * (BORDER_RIGHT - BORDER_LEFT) / 2.0f; /* remove the orange part ! */
531 ctx->height = HIWORD(lParam) * (BORDER_TOP - BORDER_BOTTOM) / 2.0f;
532 EnterCriticalSection(&ctx->sizeLock);
533 if (ctx->ReportSize != nullptr)
534 ctx->ReportSize(ctx->ReportOpaque, ctx->width, ctx->height);
535 LeaveCriticalSection(&ctx->sizeLock);
537 break;
539 case WM_DESTROY:
540 PostQuitMessage(0);
541 return 0;
543 case WM_KEYDOWN:
544 case WM_SYSKEYDOWN:
546 int key = tolower( (unsigned char)MapVirtualKey( wParam, 2 ) );
547 if (key == 'a')
549 if (AspectRatio == NULL)
550 AspectRatio = "16:10";
551 else if (strcmp(AspectRatio,"16:10")==0)
552 AspectRatio = "16:9";
553 else if (strcmp(AspectRatio,"16:9")==0)
554 AspectRatio = "4:3";
555 else if (strcmp(AspectRatio,"4:3")==0)
556 AspectRatio = "185:100";
557 else if (strcmp(AspectRatio,"185:100")==0)
558 AspectRatio = "221:100";
559 else if (strcmp(AspectRatio,"221:100")==0)
560 AspectRatio = "235:100";
561 else if (strcmp(AspectRatio,"235:100")==0)
562 AspectRatio = "239:100";
563 else if (strcmp(AspectRatio,"239:100")==0)
564 AspectRatio = "5:3";
565 else if (strcmp(AspectRatio,"5:3")==0)
566 AspectRatio = "5:4";
567 else if (strcmp(AspectRatio,"5:4")==0)
568 AspectRatio = "1:1";
569 else if (strcmp(AspectRatio,"1:1")==0)
570 AspectRatio = NULL;
571 libvlc_video_set_aspect_ratio( ctx->p_mp, AspectRatio );
573 break;
575 default: break;
578 return DefWindowProc (hWnd, message, wParam, lParam);
581 int WINAPI WinMain(HINSTANCE hInstance,
582 HINSTANCE hPrevInstance,
583 LPSTR lpCmdLine,
584 int nCmdShow)
586 WNDCLASSEX wc;
587 struct render_context Context = { };
588 char *file_path;
589 libvlc_instance_t *p_libvlc;
590 libvlc_media_t *p_media;
591 (void)hPrevInstance;
593 /* remove "" around the given path */
594 if (lpCmdLine[0] == '"')
596 file_path = strdup( lpCmdLine+1 );
597 if (file_path[strlen(file_path)-1] == '"')
598 file_path[strlen(file_path)-1] = '\0';
600 else
601 file_path = strdup( lpCmdLine );
603 p_libvlc = libvlc_new( 0, NULL );
604 p_media = libvlc_media_new_path( p_libvlc, file_path );
605 free( file_path );
606 Context.p_mp = libvlc_media_player_new_from_media( p_media );
608 InitializeCriticalSection(&Context.sizeLock);
610 ZeroMemory(&wc, sizeof(WNDCLASSEX));
612 wc.cbSize = sizeof(WNDCLASSEX);
613 wc.style = CS_HREDRAW | CS_VREDRAW;
614 wc.lpfnWndProc = WindowProc;
615 wc.hInstance = hInstance;
616 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
617 wc.lpszClassName = "WindowClass";
619 RegisterClassEx(&wc);
621 RECT wr = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
622 AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
624 Context.hWnd = CreateWindowEx(0,
625 "WindowClass",
626 "libvlc Demo app",
627 WS_OVERLAPPEDWINDOW,
628 CW_USEDEFAULT, CW_USEDEFAULT,
629 wr.right - wr.left,
630 wr.bottom - wr.top,
631 NULL,
632 NULL,
633 hInstance,
634 &Context);
636 ShowWindow(Context.hWnd, nCmdShow);
638 // DON'T use with callbacks libvlc_media_player_set_hwnd(p_mp, hWnd);
640 /* Tell VLC to render into our D3D11 environment */
641 libvlc_video_set_output_callbacks( Context.p_mp, libvlc_video_engine_d3d11,
642 Setup_cb, Cleanup_cb, Resize_cb, UpdateOutput_cb, Swap_cb, StartRendering_cb,
643 nullptr, nullptr, SelectPlane_cb,
644 &Context );
646 libvlc_media_player_play( Context.p_mp );
648 MSG msg;
650 while(TRUE)
652 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
654 TranslateMessage(&msg);
655 DispatchMessage(&msg);
657 if(msg.message == WM_QUIT)
658 break;
662 libvlc_media_player_stop_async( Context.p_mp );
664 libvlc_media_player_release( Context.p_mp );
665 libvlc_media_release( p_media );
666 libvlc_release( p_libvlc );
668 DeleteCriticalSection(&Context.sizeLock);
670 return msg.wParam;