1 /**************************************************************************
3 * Copyright 2009 Younes Manton.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
31 #include <X11/Xlibint.h>
33 #include "pipe/p_video_decoder.h"
34 #include "pipe/p_video_state.h"
35 #include "pipe/p_state.h"
37 #include "util/u_inlines.h"
38 #include "util/u_memory.h"
39 #include "util/u_math.h"
41 #include "vl_winsys.h"
43 #include "xvmc_private.h"
46 MacroBlocksToPipe(XvMCContextPrivate
*context
,
47 XvMCSurfacePrivate
*surface
,
48 unsigned int xvmc_picture_structure
,
49 const XvMCMacroBlock
*xvmc_mb
,
50 const XvMCBlockArray
*xvmc_blocks
,
51 struct pipe_mpeg12_macroblock
*mb
,
52 unsigned int num_macroblocks
)
58 assert(num_macroblocks
);
60 for (; num_macroblocks
> 0; --num_macroblocks
) {
61 mb
->base
.codec
= PIPE_VIDEO_CODEC_MPEG12
;
64 mb
->macroblock_type
= xvmc_mb
->macroblock_type
;
66 switch (xvmc_picture_structure
) {
67 case XVMC_FRAME_PICTURE
:
68 mb
->macroblock_modes
.bits
.frame_motion_type
= xvmc_mb
->motion_type
;
69 mb
->macroblock_modes
.bits
.field_motion_type
= 0;
73 case XVMC_BOTTOM_FIELD
:
74 mb
->macroblock_modes
.bits
.frame_motion_type
= 0;
75 mb
->macroblock_modes
.bits
.field_motion_type
= xvmc_mb
->motion_type
;
82 mb
->macroblock_modes
.bits
.dct_type
= xvmc_mb
->dct_type
;
83 mb
->motion_vertical_field_select
= xvmc_mb
->motion_vertical_field_select
;
85 for (i
= 0; i
< 2; ++i
)
86 for (j
= 0; j
< 2; ++j
)
87 for (k
= 0; k
< 2; ++k
)
88 mb
->PMV
[i
][j
][k
] = xvmc_mb
->PMV
[i
][j
][k
];
90 mb
->coded_block_pattern
= xvmc_mb
->coded_block_pattern
;
91 mb
->blocks
= xvmc_blocks
->blocks
+ xvmc_mb
->index
* BLOCK_SIZE_SAMPLES
;
92 mb
->num_skipped_macroblocks
= 0;
100 GetPictureDescription(XvMCSurfacePrivate
*surface
, struct pipe_mpeg12_picture_desc
*desc
)
102 unsigned i
, num_refs
= 0;
104 assert(surface
&& desc
);
106 memset(desc
, 0, sizeof(*desc
));
107 desc
->base
.profile
= PIPE_VIDEO_PROFILE_MPEG1
;
108 desc
->picture_structure
= surface
->picture_structure
;
109 for (i
= 0; i
< 2; ++i
) {
110 if (surface
->ref
[i
]) {
111 XvMCSurfacePrivate
*ref
= surface
->ref
[i
]->privData
;
114 desc
->ref
[num_refs
++] = ref
->video_buffer
;
120 RecursiveEndFrame(XvMCSurfacePrivate
*surface
)
122 XvMCContextPrivate
*context_priv
;
127 context_priv
= surface
->context
->privData
;
129 for ( i
= 0; i
< 2; ++i
) {
130 if (surface
->ref
[i
]) {
131 XvMCSurface
*ref
= surface
->ref
[i
];
135 surface
->ref
[i
] = NULL
;
136 RecursiveEndFrame(ref
->privData
);
137 surface
->ref
[i
] = ref
;
141 if (surface
->picture_structure
) {
142 struct pipe_mpeg12_picture_desc desc
;
143 GetPictureDescription(surface
, &desc
);
144 surface
->picture_structure
= 0;
146 for (i
= 0; i
< 2; ++i
)
147 surface
->ref
[i
] = NULL
;
149 context_priv
->decoder
->end_frame(context_priv
->decoder
, surface
->video_buffer
, &desc
.base
);
154 Status
XvMCCreateSurface(Display
*dpy
, XvMCContext
*context
, XvMCSurface
*surface
)
156 XvMCContextPrivate
*context_priv
;
157 struct pipe_context
*pipe
;
158 XvMCSurfacePrivate
*surface_priv
;
159 struct pipe_video_buffer tmpl
;
161 XVMC_MSG(XVMC_TRACE
, "[XvMC] Creating surface %p.\n", surface
);
166 return XvMCBadContext
;
168 return XvMCBadSurface
;
170 context_priv
= context
->privData
;
171 pipe
= context_priv
->pipe
;
173 surface_priv
= CALLOC(1, sizeof(XvMCSurfacePrivate
));
177 memset(&tmpl
, 0, sizeof(tmpl
));
178 tmpl
.buffer_format
= pipe
->screen
->get_video_param
181 PIPE_VIDEO_PROFILE_MPEG2_MAIN
,
182 PIPE_VIDEO_CAP_PREFERED_FORMAT
184 tmpl
.chroma_format
= context_priv
->decoder
->chroma_format
;
185 tmpl
.width
= context_priv
->decoder
->width
;
186 tmpl
.height
= context_priv
->decoder
->height
;
187 tmpl
.interlaced
= pipe
->screen
->get_video_param
190 PIPE_VIDEO_PROFILE_MPEG2_MAIN
,
191 PIPE_VIDEO_CAP_PREFERS_INTERLACED
194 surface_priv
->video_buffer
= pipe
->create_video_buffer(pipe
, &tmpl
);
195 surface_priv
->context
= context
;
197 surface
->surface_id
= XAllocID(dpy
);
198 surface
->context_id
= context
->context_id
;
199 surface
->surface_type_id
= context
->surface_type_id
;
200 surface
->width
= context
->width
;
201 surface
->height
= context
->height
;
202 surface
->privData
= surface_priv
;
206 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p created.\n", surface
);
212 Status
XvMCRenderSurface(Display
*dpy
, XvMCContext
*context
, unsigned int picture_structure
,
213 XvMCSurface
*target_surface
, XvMCSurface
*past_surface
, XvMCSurface
*future_surface
,
214 unsigned int flags
, unsigned int num_macroblocks
, unsigned int first_macroblock
,
215 XvMCMacroBlockArray
*macroblocks
, XvMCBlockArray
*blocks
218 struct pipe_mpeg12_macroblock mb
[num_macroblocks
];
219 struct pipe_video_decoder
*decoder
;
220 struct pipe_mpeg12_picture_desc desc
;
222 XvMCContextPrivate
*context_priv
;
223 XvMCSurfacePrivate
*target_surface_priv
;
224 XvMCSurfacePrivate
*past_surface_priv
;
225 XvMCSurfacePrivate
*future_surface_priv
;
226 XvMCMacroBlock
*xvmc_mb
;
228 XVMC_MSG(XVMC_TRACE
, "[XvMC] Rendering to surface %p, with past %p and future %p\n",
229 target_surface
, past_surface
, future_surface
);
233 if (!context
|| !context
->privData
)
234 return XvMCBadContext
;
235 if (!target_surface
|| !target_surface
->privData
)
236 return XvMCBadSurface
;
238 if (picture_structure
!= XVMC_TOP_FIELD
&&
239 picture_structure
!= XVMC_BOTTOM_FIELD
&&
240 picture_structure
!= XVMC_FRAME_PICTURE
)
242 /* Bkwd pred equivalent to fwd (past && !future) */
243 if (future_surface
&& !past_surface
)
246 assert(context
->context_id
== target_surface
->context_id
);
247 assert(!past_surface
|| context
->context_id
== past_surface
->context_id
);
248 assert(!future_surface
|| context
->context_id
== future_surface
->context_id
);
253 assert(macroblocks
->context_id
== context
->context_id
);
254 assert(blocks
->context_id
== context
->context_id
);
256 assert(flags
== 0 || flags
== XVMC_SECOND_FIELD
);
258 context_priv
= context
->privData
;
259 decoder
= context_priv
->decoder
;
261 target_surface_priv
= target_surface
->privData
;
262 past_surface_priv
= past_surface
? past_surface
->privData
: NULL
;
263 future_surface_priv
= future_surface
? future_surface
->privData
: NULL
;
265 assert(target_surface_priv
->context
== context
);
266 assert(!past_surface
|| past_surface_priv
->context
== context
);
267 assert(!future_surface
|| future_surface_priv
->context
== context
);
269 // call end frame on all referenced frames
271 RecursiveEndFrame(past_surface
->privData
);
274 RecursiveEndFrame(future_surface
->privData
);
276 xvmc_mb
= macroblocks
->macro_blocks
+ first_macroblock
;
278 /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */
279 if (target_surface_priv
->picture_structure
> 0 && (
280 target_surface_priv
->picture_structure
!= picture_structure
||
281 target_surface_priv
->ref
[0] != past_surface
||
282 target_surface_priv
->ref
[1] != future_surface
||
283 (xvmc_mb
->x
== 0 && xvmc_mb
->y
== 0))) {
285 // If they change anyway we must assume that the current frame is ended
286 RecursiveEndFrame(target_surface_priv
);
289 target_surface_priv
->ref
[0] = past_surface
;
290 target_surface_priv
->ref
[1] = future_surface
;
292 if (target_surface_priv
->picture_structure
)
293 GetPictureDescription(target_surface_priv
, &desc
);
295 target_surface_priv
->picture_structure
= picture_structure
;
296 GetPictureDescription(target_surface_priv
, &desc
);
297 decoder
->begin_frame(decoder
, target_surface_priv
->video_buffer
, &desc
.base
);
300 MacroBlocksToPipe(context_priv
, target_surface_priv
, picture_structure
,
301 xvmc_mb
, blocks
, mb
, num_macroblocks
);
303 context_priv
->decoder
->decode_macroblock(context_priv
->decoder
,
304 target_surface_priv
->video_buffer
,
306 &mb
[0].base
, num_macroblocks
);
308 XVMC_MSG(XVMC_TRACE
, "[XvMC] Submitted surface %p for rendering.\n", target_surface
);
314 Status
XvMCFlushSurface(Display
*dpy
, XvMCSurface
*surface
)
319 return XvMCBadSurface
;
321 // don't call flush here, because this is usually
322 // called once for every slice instead of every frame
324 XVMC_MSG(XVMC_TRACE
, "[XvMC] Flushing surface %p\n", surface
);
330 Status
XvMCSyncSurface(Display
*dpy
, XvMCSurface
*surface
)
335 return XvMCBadSurface
;
337 XVMC_MSG(XVMC_TRACE
, "[XvMC] Syncing surface %p\n", surface
);
343 Status
XvMCPutSurface(Display
*dpy
, XvMCSurface
*surface
, Drawable drawable
,
344 short srcx
, short srcy
, unsigned short srcw
, unsigned short srch
,
345 short destx
, short desty
, unsigned short destw
, unsigned short desth
,
348 static int dump_window
= -1;
350 struct pipe_context
*pipe
;
351 struct vl_compositor
*compositor
;
353 XvMCSurfacePrivate
*surface_priv
;
354 XvMCContextPrivate
*context_priv
;
355 XvMCSubpicturePrivate
*subpicture_priv
;
356 XvMCContext
*context
;
357 struct pipe_video_rect src_rect
= {srcx
, srcy
, srcw
, srch
};
358 struct pipe_video_rect dst_rect
= {destx
, desty
, destw
, desth
};
360 struct pipe_resource
*tex
;
361 struct pipe_surface surf_templ
, *surf
;
363 XVMC_MSG(XVMC_TRACE
, "[XvMC] Displaying surface %p.\n", surface
);
367 if (!surface
|| !surface
->privData
)
368 return XvMCBadSurface
;
370 surface_priv
= surface
->privData
;
371 context
= surface_priv
->context
;
372 context_priv
= context
->privData
;
374 assert(flags
== XVMC_TOP_FIELD
|| flags
== XVMC_BOTTOM_FIELD
|| flags
== XVMC_FRAME_PICTURE
);
375 assert(srcx
+ srcw
- 1 < surface
->width
);
376 assert(srcy
+ srch
- 1 < surface
->height
);
378 subpicture_priv
= surface_priv
->subpicture
? surface_priv
->subpicture
->privData
: NULL
;
379 pipe
= context_priv
->pipe
;
380 compositor
= &context_priv
->compositor
;
382 tex
= vl_screen_texture_from_drawable(context_priv
->vscreen
, drawable
);
383 memset(&surf_templ
, 0, sizeof(surf_templ
));
384 surf_templ
.format
= tex
->format
;
385 surf_templ
.usage
= PIPE_BIND_RENDER_TARGET
;
386 surf
= pipe
->create_surface(pipe
, tex
, &surf_templ
);
392 * Some apps (mplayer) hit these asserts because they call
393 * this function after the window has been resized by the WM
394 * but before they've handled the corresponding XEvent and
395 * know about the new dimensions. The output should be clipped
396 * until the app updates destw and desth.
399 assert(destx + destw - 1 < drawable_surface->width);
400 assert(desty + desth - 1 < drawable_surface->height);
403 RecursiveEndFrame(surface_priv
);
405 context_priv
->decoder
->flush(context_priv
->decoder
);
407 vl_compositor_clear_layers(compositor
);
408 vl_compositor_set_buffer_layer(compositor
, 0, surface_priv
->video_buffer
,
409 &src_rect
, NULL
, VL_COMPOSITOR_WEAVE
);
411 if (subpicture_priv
) {
412 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p has subpicture %p.\n", surface
, surface_priv
->subpicture
);
414 assert(subpicture_priv
->surface
== surface
);
416 if (subpicture_priv
->palette
)
417 vl_compositor_set_palette_layer(compositor
, 1, subpicture_priv
->sampler
, subpicture_priv
->palette
,
418 &subpicture_priv
->src_rect
, &subpicture_priv
->dst_rect
, true);
420 vl_compositor_set_rgba_layer(compositor
, 1, subpicture_priv
->sampler
,
421 &subpicture_priv
->src_rect
, &subpicture_priv
->dst_rect
);
423 surface_priv
->subpicture
= NULL
;
424 subpicture_priv
->surface
= NULL
;
427 // Workaround for r600g, there seems to be a bug in the fence refcounting code
428 pipe
->screen
->fence_reference(pipe
->screen
, &surface_priv
->fence
, NULL
);
430 vl_compositor_render(compositor
, surf
, &dst_rect
, NULL
, &context_priv
->dirty_area
);
432 pipe
->flush(pipe
, &surface_priv
->fence
);
434 XVMC_MSG(XVMC_TRACE
, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface
);
436 pipe
->screen
->flush_frontbuffer
438 pipe
->screen
, tex
, 0, 0,
439 vl_screen_get_private(context_priv
->vscreen
)
442 if(dump_window
== -1) {
443 dump_window
= debug_get_num_option("XVMC_DUMP", 0);
447 static unsigned int framenum
= 0;
450 sprintf(cmd
, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable
, ++framenum
);
451 if (system(cmd
) != 0)
452 XVMC_MSG(XVMC_ERR
, "[XvMC] Dumping surface %p failed.\n", surface
);
455 XVMC_MSG(XVMC_TRACE
, "[XvMC] Pushed surface %p to front buffer.\n", surface
);
461 Status
XvMCGetSurfaceStatus(Display
*dpy
, XvMCSurface
*surface
, int *status
)
463 struct pipe_context
*pipe
;
464 XvMCSurfacePrivate
*surface_priv
;
465 XvMCContextPrivate
*context_priv
;
470 return XvMCBadSurface
;
474 surface_priv
= surface
->privData
;
475 context_priv
= surface_priv
->context
->privData
;
476 pipe
= context_priv
->pipe
;
480 if (surface_priv
->fence
)
481 if (!pipe
->screen
->fence_signalled(pipe
->screen
, surface_priv
->fence
))
482 *status
|= XVMC_RENDERING
;
488 Status
XvMCDestroySurface(Display
*dpy
, XvMCSurface
*surface
)
490 XvMCSurfacePrivate
*surface_priv
;
491 XvMCContextPrivate
*context_priv
;
493 XVMC_MSG(XVMC_TRACE
, "[XvMC] Destroying surface %p.\n", surface
);
497 if (!surface
|| !surface
->privData
)
498 return XvMCBadSurface
;
500 surface_priv
= surface
->privData
;
501 context_priv
= surface_priv
->context
->privData
;
503 if (surface_priv
->picture_structure
) {
504 struct pipe_mpeg12_picture_desc desc
;
505 GetPictureDescription(surface_priv
, &desc
);
506 context_priv
->decoder
->end_frame(context_priv
->decoder
, surface_priv
->video_buffer
, &desc
.base
);
508 surface_priv
->video_buffer
->destroy(surface_priv
->video_buffer
);
510 surface
->privData
= NULL
;
512 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p destroyed.\n", surface
);
518 Status
XvMCHideSurface(Display
*dpy
, XvMCSurface
*surface
)
522 if (!surface
|| !surface
->privData
)
523 return XvMCBadSurface
;
525 /* No op, only for overlaid rendering */