Mercurial > mplayer.hg
annotate libvo/vo_direct3d.c @ 28006:c06e8f1eec97
Add support for RGB formats to vo_direct3d
author | reimar |
---|---|
date | Wed, 26 Nov 2008 16:27:39 +0000 |
parents | 1c77b86d355d |
children | 16b39ef63bb5 |
rev | line source |
---|---|
27921 | 1 /* |
2 * Copyright (c) 2008 Georgi Petrov (gogothebee) <gogothebee@gmail.com> | |
3 * | |
4 * This file is part of MPlayer. | |
5 * | |
6 * MPlayer is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * MPlayer is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License along | |
17 * with MPlayer; if not, write to the Free Software Foundation, Inc., | |
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
19 */ | |
20 | |
21 #include <windows.h> | |
22 #include <errno.h> | |
23 #include <stdio.h> | |
24 #include <d3d9.h> | |
25 #include "config.h" | |
26 #include "video_out.h" | |
27 #include "video_out_internal.h" | |
28 #include "fastmemcpy.h" | |
29 #include "mp_msg.h" | |
30 #include "aspect.h" | |
31 #include "w32_common.h" | |
27937 | 32 #include "libavutil/common.h" |
27921 | 33 |
34 static const vo_info_t info = | |
35 { | |
36 "Direct3D 9 Renderer", | |
37 "direct3d", | |
38 "Georgi Petrov (gogothebee) <gogothebee@gmail.com>", | |
39 "" | |
40 }; | |
41 | |
42 /* | |
43 * Link essential libvo functions: preinit, config, control, draw_frame, | |
44 * draw_slice, draw_osd, flip_page, check_events, uninit and | |
45 * the structure info. | |
46 */ | |
47 const LIBVO_EXTERN(direct3d) | |
48 | |
49 | |
27928 | 50 /* Global variables "priv" structure. I try to keep their count low. |
27921 | 51 */ |
27928 | 52 static struct global_priv { |
53 int is_paused; /**< 1 = Movie is paused, | |
54 0 = Movie is not paused */ | |
27984
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
55 int is_clear_needed; /**< 1 = Clear the backbuffer before StretchRect |
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
56 0 = (default) Don't clear it */ |
27968
1081658aa871
Move locked_rect from stack to priv struct in preparation for following patch.
reimar
parents:
27967
diff
changeset
|
57 D3DLOCKED_RECT locked_rect; /**< The locked Offscreen surface */ |
27928 | 58 RECT fs_movie_rect; /**< Rect (upscaled) of the movie when displayed |
59 in fullscreen */ | |
60 RECT fs_panscan_rect; /**< PanScan source surface cropping in | |
61 fullscreen */ | |
62 int src_width; /**< Source (movie) width */ | |
63 int src_height; /**< Source (movie) heigth */ | |
27921 | 64 |
27928 | 65 D3DFORMAT movie_src_fmt; /**< Movie colorspace format (depends on |
66 the movie's codec) */ | |
67 D3DFORMAT desktop_fmt; /**< Desktop (screen) colorspace format. | |
68 Usually XRGB */ | |
69 LPDIRECT3D9 d3d_handle; /**< Direct3D Handle */ | |
70 LPDIRECT3DDEVICE9 d3d_device; /**< The Direct3D Adapter */ | |
71 IDirect3DSurface9 *d3d_surface; /**< Offscreen Direct3D Surface. MPlayer | |
72 renders inside it. Uses colorspace | |
73 priv->movie_src_fmt */ | |
74 IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to | |
75 display next frame) */ | |
76 } *priv; | |
77 | |
78 typedef struct { | |
79 const unsigned int mplayer_fmt; /**< Given by MPlayer */ | |
80 const D3DFORMAT fourcc; /**< Required by D3D's test function */ | |
81 } struct_fmt_table; | |
27921 | 82 |
83 /* Map table from reported MPlayer format to the required | |
27928 | 84 fourcc. This is needed to perform the format query. */ |
27921 | 85 |
27928 | 86 static const struct_fmt_table fmt_table[] = { |
27921 | 87 {IMGFMT_YV12, MAKEFOURCC('Y','V','1','2')}, |
88 {IMGFMT_I420, MAKEFOURCC('I','4','2','0')}, | |
89 {IMGFMT_IYUV, MAKEFOURCC('I','Y','U','V')}, | |
90 {IMGFMT_YVU9, MAKEFOURCC('Y','V','U','9')}, | |
91 {IMGFMT_YUY2, MAKEFOURCC('Y','U','Y','2')}, | |
27928 | 92 {IMGFMT_UYVY, MAKEFOURCC('U','Y','V','Y')}, |
28006 | 93 {IMGFMT_BGR32, D3DFMT_X8R8G8B8}, |
94 {IMGFMT_RGB32, D3DFMT_X8B8G8R8}, | |
95 {IMGFMT_BGR24, D3DFMT_R8G8B8}, //untested | |
96 {IMGFMT_BGR16, D3DFMT_R5G6B5}, | |
97 {IMGFMT_BGR15, D3DFMT_X1R5G5B5}, | |
98 {IMGFMT_BGR8 , D3DFMT_R3G3B2}, //untested | |
27921 | 99 }; |
100 | |
101 #define DISPLAY_FORMAT_TABLE_ENTRIES \ | |
27928 | 102 (sizeof(fmt_table) / sizeof(fmt_table[0])) |
27921 | 103 |
104 /**************************************************************************** | |
105 * * | |
106 * * | |
107 * * | |
108 * Direct3D specific implementation functions * | |
109 * * | |
110 * * | |
111 * * | |
112 ****************************************************************************/ | |
113 | |
114 /** @brief Calculate scaled fullscreen movie rectangle with | |
115 * preserved aspect ratio. | |
116 */ | |
27928 | 117 static void calc_fs_rect(void) |
27921 | 118 { |
27928 | 119 int scaled_height = 0; |
120 int scaled_width = 0; | |
27921 | 121 |
27937 | 122 // set default values |
123 priv->fs_movie_rect.left = 0; | |
124 priv->fs_movie_rect.right = vo_dwidth; | |
125 priv->fs_movie_rect.top = 0; | |
126 priv->fs_movie_rect.bottom = vo_dheight; | |
127 priv->fs_panscan_rect.left = 0; | |
128 priv->fs_panscan_rect.right = priv->src_width; | |
129 priv->fs_panscan_rect.top = 0; | |
130 priv->fs_panscan_rect.bottom = priv->src_height; | |
131 if (!vo_fs) return; | |
132 | |
133 // adjust for fullscreen aspect and panscan | |
27928 | 134 aspect(&scaled_width, &scaled_height, A_ZOOM); |
27937 | 135 panscan_calc(); |
136 scaled_width += vo_panscan_x; | |
137 scaled_height += vo_panscan_y; | |
27921 | 138 |
27937 | 139 // note: border is rounded to a multiple of two since at least |
140 // ATI drivers can not handle odd values with YV12 input | |
141 if (scaled_width > vo_dwidth) { | |
142 int border = priv->src_width * (scaled_width - vo_dwidth) / scaled_width; | |
143 border = (border / 2 + 1) & ~1; | |
144 priv->fs_panscan_rect.left = border; | |
145 priv->fs_panscan_rect.right = priv->src_width - border; | |
146 } else { | |
147 priv->fs_movie_rect.left = (vo_dwidth - scaled_width) / 2; | |
148 priv->fs_movie_rect.right = priv->fs_movie_rect.left + scaled_width; | |
149 } | |
150 if (scaled_height > vo_dheight) { | |
151 int border = priv->src_height * (scaled_height - vo_dheight) / scaled_height; | |
152 border = (border / 2 + 1) & ~1; | |
153 priv->fs_panscan_rect.top = border; | |
154 priv->fs_panscan_rect.bottom = priv->src_height - border; | |
155 } else { | |
156 priv->fs_movie_rect.top = (vo_dheight - scaled_height) / 2; | |
157 priv->fs_movie_rect.bottom = priv->fs_movie_rect.top + scaled_height; | |
158 } | |
27921 | 159 |
160 mp_msg(MSGT_VO,MSGL_V, | |
161 "<vo_direct3d>Fullscreen Movie Rect: t: %ld, l: %ld, r: %ld, b:%ld\r\n", | |
27928 | 162 priv->fs_movie_rect.top, priv->fs_movie_rect.left, |
163 priv->fs_movie_rect.right, priv->fs_movie_rect.bottom); | |
27984
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
164 |
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
165 /* The backbuffer should be cleared before next StretchRect. This is |
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
166 * necessary because our new draw area could be smaller than the |
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
167 * previous one used by StretchRect and without it, leftovers from the |
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
168 * previous frame will be left. */ |
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
169 priv->is_clear_needed = 1; |
27921 | 170 } |
171 | |
172 /** @brief Destroy D3D Context related to the current window. | |
173 */ | |
27928 | 174 static void destroy_d3d_context(void) |
27921 | 175 { |
27928 | 176 mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>destroy_d3d_context called\r\n"); |
27921 | 177 /* Let's destroy the old (if any) D3D Content */ |
178 | |
27969
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
179 if (priv->locked_rect.pBits) { |
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
180 IDirect3DSurface9_UnlockRect(priv->d3d_surface); |
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
181 priv->locked_rect.pBits = NULL; |
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
182 } |
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
183 |
27928 | 184 if (priv->d3d_surface != NULL) { |
185 IDirect3DSurface9_Release (priv->d3d_surface); | |
186 priv->d3d_surface = NULL; | |
27921 | 187 } |
188 | |
27928 | 189 if (priv->d3d_device != NULL) { |
190 IDirect3DDevice9_Release (priv->d3d_device); | |
191 priv->d3d_device = NULL; | |
27921 | 192 } |
193 | |
27928 | 194 /* The following is not a memory leak. d3d_backbuf is not malloc'ed |
27921 | 195 * but just holds a pointer to the back buffer. Nobody gets hurt from |
196 * setting it to NULL. | |
197 */ | |
27928 | 198 priv->d3d_backbuf = NULL; |
27921 | 199 } |
200 | |
201 | |
202 /** @brief (Re)Initialize Direct3D. Kill and recreate context. | |
203 * The first function called to initialize D3D context. | |
204 * @return 1 on success, 0 on failure | |
205 */ | |
27928 | 206 static int reconfigure_d3d(void) |
27921 | 207 { |
27928 | 208 D3DPRESENT_PARAMETERS present_params; |
209 D3DDISPLAYMODE disp_mode; | |
27921 | 210 |
27928 | 211 mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d><INFO>reconfigure_d3d called \n"); |
27921 | 212 |
27928 | 213 destroy_d3d_context(); |
27921 | 214 |
215 /* Get the current desktop display mode, so we can set up a back buffer | |
216 * of the same format. */ | |
27928 | 217 if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle, |
218 D3DADAPTER_DEFAULT, | |
219 &disp_mode))) { | |
27921 | 220 mp_msg(MSGT_VO,MSGL_ERR, |
221 "<vo_direct3d><INFO>Could not read adapter display mode.\n"); | |
222 return 0; | |
223 } | |
224 | |
225 /* Write current Desktop's colorspace format in the global storage. */ | |
27928 | 226 priv->desktop_fmt = disp_mode.Format; |
27921 | 227 |
228 /* Prepare Direct3D initialization parameters. */ | |
27928 | 229 memset(&present_params, 0, sizeof(D3DPRESENT_PARAMETERS)); |
230 present_params.Windowed = TRUE; | |
231 present_params.SwapEffect = D3DSWAPEFFECT_COPY; | |
232 present_params.Flags = D3DPRESENTFLAG_VIDEO; | |
233 present_params.hDeviceWindow = vo_w32_window; /* w32_common var */ | |
234 present_params.BackBufferWidth = 0; /* Fill up window Width */ | |
235 present_params.BackBufferHeight = 0; /* Fill up window Height */ | |
236 present_params.MultiSampleType = D3DMULTISAMPLE_NONE; | |
27921 | 237 /* D3DPRESENT_INTERVAL_ONE = vsync */ |
27928 | 238 present_params.PresentationInterval = D3DPRESENT_INTERVAL_ONE; |
239 present_params.BackBufferFormat = priv->desktop_fmt; | |
240 present_params.BackBufferCount = 1; | |
241 present_params.EnableAutoDepthStencil = FALSE; | |
27921 | 242 |
243 /* vo_w32_window is w32_common variable. It's a handle to the window. */ | |
27928 | 244 if (FAILED(IDirect3D9_CreateDevice(priv->d3d_handle, |
27921 | 245 D3DADAPTER_DEFAULT, |
246 D3DDEVTYPE_HAL, vo_w32_window, | |
247 D3DCREATE_SOFTWARE_VERTEXPROCESSING, | |
27928 | 248 &present_params, &priv->d3d_device))) { |
27921 | 249 mp_msg(MSGT_VO,MSGL_ERR, |
250 "<vo_direct3d><INFO>Could not create the D3D device\n"); | |
251 return 0; | |
252 } | |
253 | |
254 mp_msg(MSGT_VO,MSGL_V, | |
255 "New BackBuffer: Width: %d, Height:%d. VO Dest Width:%d, Height: %d\n", | |
27928 | 256 present_params.BackBufferWidth, present_params.BackBufferHeight, |
27921 | 257 vo_dwidth, vo_dheight); |
258 | |
27928 | 259 if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( |
260 priv->d3d_device, priv->src_width, priv->src_height, | |
261 priv->movie_src_fmt, D3DPOOL_DEFAULT, &priv->d3d_surface, NULL))) { | |
27921 | 262 mp_msg(MSGT_VO,MSGL_ERR, |
263 "<vo_direct3d><INFO>IDirect3D9_CreateOffscreenPlainSurface Failed.\n"); | |
264 return 0; | |
265 } | |
266 | |
27928 | 267 if (FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, |
268 D3DBACKBUFFER_TYPE_MONO, | |
269 &(priv->d3d_backbuf)))) { | |
27921 | 270 mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Back Buffer address get failed\n"); |
271 return 0; | |
272 } | |
273 | |
27937 | 274 calc_fs_rect(); |
27921 | 275 |
276 return 1; | |
277 } | |
278 | |
279 /** @brief Uninitialize Direct3D and close the window. | |
280 */ | |
27928 | 281 static void uninit_d3d(void) |
27921 | 282 { |
27928 | 283 mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>uninit_d3d called\r\n"); |
27921 | 284 |
285 /* Destroy D3D Context inside the window. */ | |
27928 | 286 destroy_d3d_context(); |
27921 | 287 |
288 /* Stop the whole D3D. */ | |
27928 | 289 if (NULL != priv->d3d_handle) { |
27921 | 290 mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Calling IDirect3D9_Release\r\n"); |
27928 | 291 IDirect3D9_Release(priv->d3d_handle); |
27921 | 292 } |
293 } | |
294 | |
295 /** @brief Render a frame on the screen. | |
296 * @param mpi mpi structure with the decoded frame inside | |
297 * @return VO_TRUE on success, VO_ERROR on failure | |
298 */ | |
27928 | 299 static uint32_t render_d3d_frame(mp_image_t *mpi) |
27921 | 300 { |
301 /* Uncomment when direct rendering is implemented. | |
302 * if (mpi->flags & MP_IMGFLAG_DIRECT) ... | |
303 */ | |
304 | |
305 if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) | |
27967
ad71ce76c6ce
Move the StretchRect call from draw_slices to render_d3d_frame.
reimar
parents:
27966
diff
changeset
|
306 goto skip_upload; |
27921 | 307 |
27928 | 308 if (mpi->flags & MP_IMGFLAG_PLANAR) { /* Copy a planar frame. */ |
27921 | 309 draw_slice(mpi->planes,mpi->stride,mpi->w,mpi->h,0,0); |
27967
ad71ce76c6ce
Move the StretchRect call from draw_slices to render_d3d_frame.
reimar
parents:
27966
diff
changeset
|
310 goto skip_upload; |
27921 | 311 } |
312 | |
27969
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
313 /* If we're here, then we should lock the rect and copy a packed frame */ |
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
314 if (!priv->locked_rect.pBits) { |
27970 | 315 if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, |
316 &priv->locked_rect, NULL, 0))) { | |
317 mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Surface lock failure\n"); | |
318 return VO_ERROR; | |
319 } | |
27969
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
320 } |
27921 | 321 |
27968
1081658aa871
Move locked_rect from stack to priv struct in preparation for following patch.
reimar
parents:
27967
diff
changeset
|
322 memcpy_pic(priv->locked_rect.pBits, mpi->planes[0], mpi->stride[0], |
1081658aa871
Move locked_rect from stack to priv struct in preparation for following patch.
reimar
parents:
27967
diff
changeset
|
323 mpi->height, priv->locked_rect.Pitch, mpi->stride[0]); |
27921 | 324 |
27969
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
325 skip_upload: |
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
326 /* This unlock is used for both slice_draw path and render_d3d_frame path. */ |
27928 | 327 if (FAILED(IDirect3DSurface9_UnlockRect(priv->d3d_surface))) { |
27921 | 328 mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Surface unlock failure\n"); |
329 return VO_ERROR; | |
330 } | |
27969
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
331 priv->locked_rect.pBits = NULL; |
27921 | 332 |
27967
ad71ce76c6ce
Move the StretchRect call from draw_slices to render_d3d_frame.
reimar
parents:
27966
diff
changeset
|
333 if (FAILED(IDirect3DDevice9_BeginScene(priv->d3d_device))) { |
27970 | 334 mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>BeginScene failed\n"); |
335 return VO_ERROR; | |
27967
ad71ce76c6ce
Move the StretchRect call from draw_slices to render_d3d_frame.
reimar
parents:
27966
diff
changeset
|
336 } |
ad71ce76c6ce
Move the StretchRect call from draw_slices to render_d3d_frame.
reimar
parents:
27966
diff
changeset
|
337 |
27984
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
338 if (priv->is_clear_needed) { |
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
339 IDirect3DDevice9_Clear (priv->d3d_device, 0, NULL, |
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
340 D3DCLEAR_TARGET, 0, 0, 0); |
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
341 priv->is_clear_needed = 0; |
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
342 } |
21221fd6d994
Make sure the backbuffer is cleared when the border size might have changed.
reimar
parents:
27971
diff
changeset
|
343 |
27928 | 344 if (FAILED(IDirect3DDevice9_StretchRect(priv->d3d_device, |
345 priv->d3d_surface, | |
27937 | 346 &priv->fs_panscan_rect, |
27928 | 347 priv->d3d_backbuf, |
27937 | 348 &priv->fs_movie_rect, |
27928 | 349 D3DTEXF_LINEAR))) { |
27921 | 350 mp_msg(MSGT_VO,MSGL_ERR, |
351 "<vo_direct3d>Unable to copy the frame to the back buffer\n"); | |
352 return VO_ERROR; | |
353 } | |
354 | |
27928 | 355 if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) { |
27921 | 356 mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>EndScene failed\n"); |
357 return VO_ERROR; | |
358 } | |
359 | |
360 return VO_TRUE; | |
361 } | |
362 | |
363 | |
364 /** @brief Query if movie colorspace is supported by the HW. | |
365 * @return 0 on failure, device capabilities (not probed | |
366 * currently) on success. | |
367 */ | |
27928 | 368 static int query_format(uint32_t movie_fmt) |
27921 | 369 { |
370 int i; | |
27928 | 371 for (i=0; i < DISPLAY_FORMAT_TABLE_ENTRIES; i++) { |
372 if (fmt_table[i].mplayer_fmt == movie_fmt) { | |
27921 | 373 /* Test conversion from Movie colorspace to |
374 * display's target colorspace. */ | |
27928 | 375 if (FAILED(IDirect3D9_CheckDeviceFormatConversion( |
376 priv->d3d_handle, | |
27921 | 377 D3DADAPTER_DEFAULT, |
378 D3DDEVTYPE_HAL, | |
27928 | 379 fmt_table[i].fourcc, |
380 priv->desktop_fmt))) { | |
381 mp_msg(MSGT_VO,MSGL_V, | |
382 "<vo_direct3d>Rejected image format: %s\n", | |
383 vo_format_name(fmt_table[i].mplayer_fmt)); | |
384 return 0; | |
385 } | |
27921 | 386 |
27928 | 387 priv->movie_src_fmt = fmt_table[i].fourcc; |
388 mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Accepted image format: %s\n", | |
389 vo_format_name(fmt_table[i].mplayer_fmt)); | |
27921 | 390 return (VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW |
391 /*| VFCAP_OSD*/ | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN); | |
392 | |
393 } | |
394 } | |
395 | |
396 return 0; | |
397 } | |
398 | |
399 /**************************************************************************** | |
400 * * | |
401 * * | |
402 * * | |
403 * libvo Control / Callback functions * | |
404 * * | |
405 * * | |
406 * * | |
407 ****************************************************************************/ | |
408 | |
409 | |
410 | |
411 | |
412 /** @brief libvo Callback: Preinitialize the video card. | |
413 * Preinit the hardware just enough to be queried about | |
414 * supported formats. | |
415 * | |
416 * @return 0 on success, -1 on failure | |
417 */ | |
27928 | 418 |
27921 | 419 static int preinit(const char *arg) |
420 { | |
27928 | 421 D3DDISPLAYMODE disp_mode; |
422 | |
27921 | 423 /* Set to zero all global variables. */ |
27928 | 424 priv = calloc(1, sizeof (struct global_priv)); |
425 if (!priv) { | |
426 mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Not enough memory\r\n"); | |
427 return -1; | |
428 } | |
27921 | 429 |
430 /* FIXME | |
431 > Please use subopt-helper.h for this, see vo_gl.c:preinit for | |
432 > an example of how to use it. | |
433 */ | |
434 | |
27928 | 435 priv->d3d_handle = Direct3DCreate9(D3D_SDK_VERSION); |
436 if (!priv->d3d_handle) { | |
27921 | 437 mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Unable to initialize Direct3D\n"); |
438 return -1; | |
439 } | |
440 | |
27928 | 441 if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle, |
442 D3DADAPTER_DEFAULT, | |
443 &disp_mode))) { | |
27921 | 444 mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Could not read display mode\n"); |
445 return -1; | |
446 } | |
447 | |
27928 | 448 /* Store in priv->desktop_fmt the user desktop's colorspace. Usually XRGB. */ |
449 priv->desktop_fmt = disp_mode.Format; | |
27921 | 450 |
27928 | 451 mp_msg(MSGT_VO,MSGL_V,"disp_mode.Width %d, disp_mode.Height %d\n", |
452 disp_mode.Width, disp_mode.Height); | |
27921 | 453 |
454 /* w32_common framework call. Configures window on the screen, gets | |
455 * fullscreen dimensions and does other useful stuff. | |
456 */ | |
27928 | 457 if (!vo_w32_init()) { |
27921 | 458 mp_msg(MSGT_VO,MSGL_V,"Unable to configure onscreen window\r\n"); |
459 return -1; | |
460 } | |
461 | |
462 return 0; | |
463 } | |
464 | |
465 | |
466 | |
467 /** @brief libvo Callback: Handle control requests. | |
468 * @return VO_TRUE on success, VO_NOTIMPL when not implemented | |
469 */ | |
470 static int control(uint32_t request, void *data, ...) | |
471 { | |
27928 | 472 switch (request) { |
27921 | 473 case VOCTRL_QUERY_FORMAT: |
27928 | 474 return query_format(*(uint32_t*) data); |
27921 | 475 case VOCTRL_GET_IMAGE: /* Direct Rendering. Not implemented yet. */ |
476 mp_msg(MSGT_VO,MSGL_V, | |
477 "<vo_direct3d>Direct Rendering request. Not implemented yet\n"); | |
478 return VO_NOTIMPL; | |
479 case VOCTRL_DRAW_IMAGE: | |
27928 | 480 return render_d3d_frame(data); |
27921 | 481 case VOCTRL_FULLSCREEN: |
482 vo_w32_fullscreen(); | |
27928 | 483 reconfigure_d3d(); |
27921 | 484 return VO_TRUE; |
485 case VOCTRL_RESET: | |
486 return VO_NOTIMPL; | |
487 case VOCTRL_PAUSE: | |
27928 | 488 priv->is_paused = 1; |
27921 | 489 return VO_TRUE; |
490 case VOCTRL_RESUME: | |
27928 | 491 priv->is_paused = 0; |
27921 | 492 return VO_TRUE; |
493 case VOCTRL_GUISUPPORT: | |
494 return VO_NOTIMPL; | |
495 case VOCTRL_SET_EQUALIZER: | |
496 return VO_NOTIMPL; | |
497 case VOCTRL_GET_EQUALIZER: | |
498 return VO_NOTIMPL; | |
499 case VOCTRL_ONTOP: | |
500 vo_w32_ontop(); | |
501 return VO_TRUE; | |
502 case VOCTRL_BORDER: | |
503 vo_w32_border(); | |
27928 | 504 reconfigure_d3d(); |
27921 | 505 return VO_TRUE; |
506 case VOCTRL_UPDATE_SCREENINFO: | |
507 w32_update_xinerama_info(); | |
508 return VO_TRUE; | |
509 case VOCTRL_SET_PANSCAN: | |
27937 | 510 calc_fs_rect (); |
27921 | 511 return VO_TRUE; |
512 case VOCTRL_GET_PANSCAN: | |
513 return VO_TRUE; | |
514 } | |
515 return VO_FALSE; | |
516 } | |
517 | |
518 /** @brief libvo Callback: Configre the Direct3D adapter. | |
519 * @param width Movie source width | |
520 * @param height Movie source height | |
521 * @param d_width Screen (destination) width | |
522 * @param d_height Screen (destination) height | |
523 * @param options Options bitmap | |
524 * @param title Window title | |
525 * @param format Movie colorspace format (using MPlayer's | |
526 * defines, e.g. IMGFMT_YUY2) | |
527 * @return 0 on success, VO_ERROR on failure | |
528 */ | |
529 static int config(uint32_t width, uint32_t height, uint32_t d_width, | |
530 uint32_t d_height, uint32_t options, char *title, | |
531 uint32_t format) | |
532 { | |
27928 | 533 |
534 priv->src_width = width; | |
535 priv->src_height = height; | |
27921 | 536 |
537 /* w32_common framework call. Creates window on the screen with | |
538 * the given coordinates. | |
539 */ | |
27928 | 540 if (!vo_w32_config(d_width, d_height, options)) { |
27921 | 541 mp_msg(MSGT_VO,MSGL_V,"Unable to create onscreen window\r\n"); |
542 return VO_ERROR; | |
543 } | |
544 | |
27966 | 545 if (!reconfigure_d3d()) |
546 return VO_ERROR; | |
547 | |
27921 | 548 return 0; /* Success */ |
549 } | |
550 | |
551 /** @brief libvo Callback: Flip next already drawn frame on the | |
552 * screen. | |
553 * @return N/A | |
554 */ | |
555 static void flip_page(void) | |
556 { | |
27928 | 557 if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, 0, 0, 0, 0))) { |
27921 | 558 mp_msg(MSGT_VO,MSGL_V, |
559 "<vo_direct3d>Video adapter became uncooperative.\n"); | |
560 mp_msg(MSGT_VO,MSGL_ERR,"<vo_direct3d>Trying to reinitialize it...\n"); | |
27928 | 561 if (!reconfigure_d3d()) { |
27921 | 562 mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Reinitialization Failed.\n"); |
563 return; | |
564 } | |
27928 | 565 if (FAILED(IDirect3DDevice9_Present(priv->d3d_device, 0, 0, 0, 0))) { |
27921 | 566 mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Reinitialization Failed.\n"); |
567 return; | |
568 } | |
569 else | |
570 mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Video adapter reinitialized.\n"); | |
571 | |
572 } | |
573 } | |
574 | |
575 /** @brief libvo Callback: Draw OSD/Subtitles, | |
576 * @return N/A | |
577 */ | |
578 static void draw_osd(void) | |
579 { | |
580 } | |
581 | |
582 /** @brief libvo Callback: Uninitializes all pointers and closes | |
583 * all D3D related stuff, | |
584 * @return N/A | |
585 */ | |
586 static void uninit(void) | |
587 { | |
588 mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Uninitialization\r\n"); | |
589 | |
27928 | 590 uninit_d3d(); |
27921 | 591 vo_w32_uninit(); /* w32_common framework call */ |
27928 | 592 free (priv); |
593 priv = NULL; | |
27921 | 594 } |
595 | |
596 /** @brief libvo Callback: Handles video window events. | |
597 * @return N/A | |
598 */ | |
599 static void check_events(void) | |
600 { | |
601 int flags; | |
602 /* w32_common framework call. Handles video window events. | |
603 * Updates global libvo's vo_dwidth/vo_dheight upon resize | |
604 * with the new window width/height. | |
605 */ | |
606 flags = vo_w32_check_events(); | |
607 if (flags & VO_EVENT_RESIZE) | |
27928 | 608 reconfigure_d3d(); |
27921 | 609 |
27928 | 610 if ((flags & VO_EVENT_EXPOSE) && priv->is_paused) |
27921 | 611 flip_page(); |
612 } | |
613 | |
614 /** @brief libvo Callback: Draw slice | |
615 * @return 0 on success | |
616 */ | |
617 static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y ) | |
618 { | |
27971 | 619 char *my_src; /**< Pointer to the source image */ |
620 char *dst; /**< Pointer to the destination image */ | |
621 int uv_stride; /**< Stride of the U/V planes */ | |
27921 | 622 |
27969
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
623 /* Lock the offscreen surface if it's not already locked. */ |
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
624 if (!priv->locked_rect.pBits) { |
27970 | 625 if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, |
626 &priv->locked_rect, NULL, 0))) { | |
627 mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>Surface lock failure\n"); | |
628 return VO_FALSE; | |
629 } | |
27969
7ddd69cf214f
Lock/unlock surface only once even when drawing many slices.
reimar
parents:
27968
diff
changeset
|
630 } |
27921 | 631 |
27971 | 632 uv_stride = priv->locked_rect.Pitch / 2; |
27921 | 633 |
634 /* Copy Y */ | |
27971 | 635 dst = priv->locked_rect.pBits; |
636 dst = dst + priv->locked_rect.Pitch * y + x; | |
637 my_src=src[0]; | |
638 memcpy_pic(dst, my_src, w, h, priv->locked_rect.Pitch, stride[0]); | |
27921 | 639 |
640 w/=2;h/=2;x/=2;y/=2; | |
641 | |
642 /* Copy U */ | |
27971 | 643 dst = priv->locked_rect.pBits; |
644 dst = dst + priv->locked_rect.Pitch * priv->src_height | |
645 + uv_stride * y + x; | |
27928 | 646 if (priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2')) |
27971 | 647 my_src=src[2]; |
27921 | 648 else |
27971 | 649 my_src=src[1]; |
27921 | 650 |
27971 | 651 memcpy_pic(dst, my_src, w, h, uv_stride, stride[1]); |
27921 | 652 |
653 /* Copy V */ | |
27971 | 654 dst = priv->locked_rect.pBits; |
655 dst = dst + priv->locked_rect.Pitch * priv->src_height | |
656 + uv_stride * (priv->src_height / 2) + uv_stride * y + x; | |
27928 | 657 if (priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2')) |
27971 | 658 my_src=src[1]; |
27921 | 659 else |
27971 | 660 my_src=src[2]; |
27921 | 661 |
27971 | 662 memcpy_pic(dst, my_src, w, h, uv_stride, stride[2]); |
27921 | 663 |
664 return 0; /* Success */ | |
665 } | |
666 | |
667 /** @brief libvo Callback: Unused function | |
668 * @return N/A | |
669 */ | |
670 static int draw_frame(uint8_t *src[]) | |
671 { | |
672 mp_msg(MSGT_VO,MSGL_V,"<vo_direct3d>draw_frame called\n"); | |
673 return VO_FALSE; | |
674 } |