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"
40 #include "vl/vl_winsys.h"
42 #include "xvmc_private.h"
45 MacroBlocksToPipe(XvMCContextPrivate
*context
,
46 XvMCSurfacePrivate
*surface
,
47 unsigned int xvmc_picture_structure
,
48 const XvMCMacroBlock
*xvmc_mb
,
49 const XvMCBlockArray
*xvmc_blocks
,
50 struct pipe_mpeg12_macroblock
*mb
,
51 unsigned int num_macroblocks
)
57 assert(num_macroblocks
);
59 for (; num_macroblocks
> 0; --num_macroblocks
) {
60 mb
->base
.codec
= PIPE_VIDEO_CODEC_MPEG12
;
63 mb
->macroblock_type
= xvmc_mb
->macroblock_type
;
65 switch (xvmc_picture_structure
) {
66 case XVMC_FRAME_PICTURE
:
67 mb
->macroblock_modes
.bits
.frame_motion_type
= xvmc_mb
->motion_type
;
68 mb
->macroblock_modes
.bits
.field_motion_type
= 0;
72 case XVMC_BOTTOM_FIELD
:
73 mb
->macroblock_modes
.bits
.frame_motion_type
= 0;
74 mb
->macroblock_modes
.bits
.field_motion_type
= xvmc_mb
->motion_type
;
81 mb
->macroblock_modes
.bits
.dct_type
= xvmc_mb
->dct_type
;
82 mb
->motion_vertical_field_select
= xvmc_mb
->motion_vertical_field_select
;
84 for (i
= 0; i
< 2; ++i
)
85 for (j
= 0; j
< 2; ++j
)
86 for (k
= 0; k
< 2; ++k
)
87 mb
->PMV
[i
][j
][k
] = xvmc_mb
->PMV
[i
][j
][k
];
89 mb
->coded_block_pattern
= xvmc_mb
->coded_block_pattern
;
90 mb
->blocks
= xvmc_blocks
->blocks
+ xvmc_mb
->index
* BLOCK_SIZE_SAMPLES
;
91 mb
->num_skipped_macroblocks
= 0;
99 GetPictureDescription(XvMCSurfacePrivate
*surface
, struct pipe_mpeg12_picture_desc
*desc
)
101 unsigned i
, num_refs
= 0;
103 assert(surface
&& desc
);
105 memset(desc
, 0, sizeof(*desc
));
106 desc
->base
.profile
= PIPE_VIDEO_PROFILE_MPEG1
;
107 desc
->picture_structure
= surface
->picture_structure
;
108 for (i
= 0; i
< 2; ++i
) {
109 if (surface
->ref
[i
]) {
110 XvMCSurfacePrivate
*ref
= surface
->ref
[i
]->privData
;
113 desc
->ref
[num_refs
++] = ref
->video_buffer
;
119 RecursiveEndFrame(XvMCSurfacePrivate
*surface
)
121 XvMCContextPrivate
*context_priv
;
126 context_priv
= surface
->context
->privData
;
128 for ( i
= 0; i
< 2; ++i
) {
129 if (surface
->ref
[i
]) {
130 XvMCSurface
*ref
= surface
->ref
[i
];
134 surface
->ref
[i
] = NULL
;
135 RecursiveEndFrame(ref
->privData
);
136 surface
->ref
[i
] = ref
;
140 if (surface
->picture_structure
) {
141 struct pipe_mpeg12_picture_desc desc
;
142 GetPictureDescription(surface
, &desc
);
143 surface
->picture_structure
= 0;
145 for (i
= 0; i
< 2; ++i
)
146 surface
->ref
[i
] = NULL
;
148 context_priv
->decoder
->end_frame(context_priv
->decoder
, surface
->video_buffer
, &desc
.base
);
153 Status
XvMCCreateSurface(Display
*dpy
, XvMCContext
*context
, XvMCSurface
*surface
)
155 XvMCContextPrivate
*context_priv
;
156 struct pipe_context
*pipe
;
157 XvMCSurfacePrivate
*surface_priv
;
158 struct pipe_video_buffer tmpl
;
160 XVMC_MSG(XVMC_TRACE
, "[XvMC] Creating surface %p.\n", surface
);
165 return XvMCBadContext
;
167 return XvMCBadSurface
;
169 context_priv
= context
->privData
;
170 pipe
= context_priv
->pipe
;
172 surface_priv
= CALLOC(1, sizeof(XvMCSurfacePrivate
));
176 memset(&tmpl
, 0, sizeof(tmpl
));
177 tmpl
.buffer_format
= pipe
->screen
->get_video_param
180 PIPE_VIDEO_PROFILE_MPEG2_MAIN
,
181 PIPE_VIDEO_CAP_PREFERED_FORMAT
183 tmpl
.chroma_format
= context_priv
->decoder
->chroma_format
;
184 tmpl
.width
= context_priv
->decoder
->width
;
185 tmpl
.height
= context_priv
->decoder
->height
;
186 tmpl
.interlaced
= pipe
->screen
->get_video_param
189 PIPE_VIDEO_PROFILE_MPEG2_MAIN
,
190 PIPE_VIDEO_CAP_PREFERS_INTERLACED
193 surface_priv
->video_buffer
= pipe
->create_video_buffer(pipe
, &tmpl
);
194 surface_priv
->context
= context
;
196 surface
->surface_id
= XAllocID(dpy
);
197 surface
->context_id
= context
->context_id
;
198 surface
->surface_type_id
= context
->surface_type_id
;
199 surface
->width
= context
->width
;
200 surface
->height
= context
->height
;
201 surface
->privData
= surface_priv
;
205 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p created.\n", surface
);
211 Status
XvMCRenderSurface(Display
*dpy
, XvMCContext
*context
, unsigned int picture_structure
,
212 XvMCSurface
*target_surface
, XvMCSurface
*past_surface
, XvMCSurface
*future_surface
,
213 unsigned int flags
, unsigned int num_macroblocks
, unsigned int first_macroblock
,
214 XvMCMacroBlockArray
*macroblocks
, XvMCBlockArray
*blocks
217 struct pipe_mpeg12_macroblock mb
[num_macroblocks
];
218 struct pipe_video_decoder
*decoder
;
219 struct pipe_mpeg12_picture_desc desc
;
221 XvMCContextPrivate
*context_priv
;
222 XvMCSurfacePrivate
*target_surface_priv
;
223 XvMCSurfacePrivate
*past_surface_priv
;
224 XvMCSurfacePrivate
*future_surface_priv
;
225 XvMCMacroBlock
*xvmc_mb
;
227 XVMC_MSG(XVMC_TRACE
, "[XvMC] Rendering to surface %p, with past %p and future %p\n",
228 target_surface
, past_surface
, future_surface
);
232 if (!context
|| !context
->privData
)
233 return XvMCBadContext
;
234 if (!target_surface
|| !target_surface
->privData
)
235 return XvMCBadSurface
;
237 if (picture_structure
!= XVMC_TOP_FIELD
&&
238 picture_structure
!= XVMC_BOTTOM_FIELD
&&
239 picture_structure
!= XVMC_FRAME_PICTURE
)
241 /* Bkwd pred equivalent to fwd (past && !future) */
242 if (future_surface
&& !past_surface
)
245 assert(context
->context_id
== target_surface
->context_id
);
246 assert(!past_surface
|| context
->context_id
== past_surface
->context_id
);
247 assert(!future_surface
|| context
->context_id
== future_surface
->context_id
);
252 assert(macroblocks
->context_id
== context
->context_id
);
253 assert(blocks
->context_id
== context
->context_id
);
255 assert(flags
== 0 || flags
== XVMC_SECOND_FIELD
);
257 context_priv
= context
->privData
;
258 decoder
= context_priv
->decoder
;
260 target_surface_priv
= target_surface
->privData
;
261 past_surface_priv
= past_surface
? past_surface
->privData
: NULL
;
262 future_surface_priv
= future_surface
? future_surface
->privData
: NULL
;
264 assert(target_surface_priv
->context
== context
);
265 assert(!past_surface
|| past_surface_priv
->context
== context
);
266 assert(!future_surface
|| future_surface_priv
->context
== context
);
268 // call end frame on all referenced frames
270 RecursiveEndFrame(past_surface
->privData
);
273 RecursiveEndFrame(future_surface
->privData
);
275 xvmc_mb
= macroblocks
->macro_blocks
+ first_macroblock
;
277 /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */
278 if (target_surface_priv
->picture_structure
> 0 && (
279 target_surface_priv
->picture_structure
!= picture_structure
||
280 target_surface_priv
->ref
[0] != past_surface
||
281 target_surface_priv
->ref
[1] != future_surface
||
282 (xvmc_mb
->x
== 0 && xvmc_mb
->y
== 0))) {
284 // If they change anyway we must assume that the current frame is ended
285 RecursiveEndFrame(target_surface_priv
);
288 target_surface_priv
->ref
[0] = past_surface
;
289 target_surface_priv
->ref
[1] = future_surface
;
291 if (target_surface_priv
->picture_structure
)
292 GetPictureDescription(target_surface_priv
, &desc
);
294 target_surface_priv
->picture_structure
= picture_structure
;
295 GetPictureDescription(target_surface_priv
, &desc
);
296 decoder
->begin_frame(decoder
, target_surface_priv
->video_buffer
, &desc
.base
);
299 MacroBlocksToPipe(context_priv
, target_surface_priv
, picture_structure
,
300 xvmc_mb
, blocks
, mb
, num_macroblocks
);
302 context_priv
->decoder
->decode_macroblock(context_priv
->decoder
,
303 target_surface_priv
->video_buffer
,
305 &mb
[0].base
, num_macroblocks
);
307 XVMC_MSG(XVMC_TRACE
, "[XvMC] Submitted surface %p for rendering.\n", target_surface
);
313 Status
XvMCFlushSurface(Display
*dpy
, XvMCSurface
*surface
)
318 return XvMCBadSurface
;
320 // don't call flush here, because this is usually
321 // called once for every slice instead of every frame
323 XVMC_MSG(XVMC_TRACE
, "[XvMC] Flushing surface %p\n", surface
);
329 Status
XvMCSyncSurface(Display
*dpy
, XvMCSurface
*surface
)
334 return XvMCBadSurface
;
336 XVMC_MSG(XVMC_TRACE
, "[XvMC] Syncing surface %p\n", surface
);
342 Status
XvMCPutSurface(Display
*dpy
, XvMCSurface
*surface
, Drawable drawable
,
343 short srcx
, short srcy
, unsigned short srcw
, unsigned short srch
,
344 short destx
, short desty
, unsigned short destw
, unsigned short desth
,
347 static int dump_window
= -1;
349 struct pipe_context
*pipe
;
350 struct vl_compositor
*compositor
;
351 struct vl_compositor_state
*cstate
;
353 XvMCSurfacePrivate
*surface_priv
;
354 XvMCContextPrivate
*context_priv
;
355 XvMCSubpicturePrivate
*subpicture_priv
;
356 XvMCContext
*context
;
357 struct u_rect src_rect
= {srcx
, srcx
+ srcw
, srcy
, srcy
+ srch
};
358 struct u_rect dst_rect
= {destx
, destx
+ destw
, desty
, desty
+ desth
};
360 struct pipe_resource
*tex
;
361 struct pipe_surface surf_templ
, *surf
;
362 struct u_rect
*dirty_area
;
364 XVMC_MSG(XVMC_TRACE
, "[XvMC] Displaying surface %p.\n", surface
);
368 if (!surface
|| !surface
->privData
)
369 return XvMCBadSurface
;
371 surface_priv
= surface
->privData
;
372 context
= surface_priv
->context
;
373 context_priv
= context
->privData
;
375 assert(flags
== XVMC_TOP_FIELD
|| flags
== XVMC_BOTTOM_FIELD
|| flags
== XVMC_FRAME_PICTURE
);
376 assert(srcx
+ srcw
- 1 < surface
->width
);
377 assert(srcy
+ srch
- 1 < surface
->height
);
379 subpicture_priv
= surface_priv
->subpicture
? surface_priv
->subpicture
->privData
: NULL
;
380 pipe
= context_priv
->pipe
;
381 compositor
= &context_priv
->compositor
;
382 cstate
= &context_priv
->cstate
;
384 tex
= vl_screen_texture_from_drawable(context_priv
->vscreen
, drawable
);
385 dirty_area
= vl_screen_get_dirty_area(context_priv
->vscreen
);
387 memset(&surf_templ
, 0, sizeof(surf_templ
));
388 surf_templ
.format
= tex
->format
;
389 surf
= pipe
->create_surface(pipe
, tex
, &surf_templ
);
395 * Some apps (mplayer) hit these asserts because they call
396 * this function after the window has been resized by the WM
397 * but before they've handled the corresponding XEvent and
398 * know about the new dimensions. The output should be clipped
399 * until the app updates destw and desth.
402 assert(destx + destw - 1 < drawable_surface->width);
403 assert(desty + desth - 1 < drawable_surface->height);
406 RecursiveEndFrame(surface_priv
);
408 context_priv
->decoder
->flush(context_priv
->decoder
);
410 vl_compositor_clear_layers(cstate
);
411 vl_compositor_set_buffer_layer(cstate
, compositor
, 0, surface_priv
->video_buffer
,
412 &src_rect
, NULL
, VL_COMPOSITOR_WEAVE
);
414 if (subpicture_priv
) {
415 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p has subpicture %p.\n", surface
, surface_priv
->subpicture
);
417 assert(subpicture_priv
->surface
== surface
);
419 if (subpicture_priv
->palette
)
420 vl_compositor_set_palette_layer(cstate
, compositor
, 1, subpicture_priv
->sampler
, subpicture_priv
->palette
,
421 &subpicture_priv
->src_rect
, &subpicture_priv
->dst_rect
, true);
423 vl_compositor_set_rgba_layer(cstate
, compositor
, 1, subpicture_priv
->sampler
,
424 &subpicture_priv
->src_rect
, &subpicture_priv
->dst_rect
, NULL
);
426 surface_priv
->subpicture
= NULL
;
427 subpicture_priv
->surface
= NULL
;
430 // Workaround for r600g, there seems to be a bug in the fence refcounting code
431 pipe
->screen
->fence_reference(pipe
->screen
, &surface_priv
->fence
, NULL
);
433 vl_compositor_set_layer_dst_area(cstate
, 0, &dst_rect
);
434 vl_compositor_set_layer_dst_area(cstate
, 1, &dst_rect
);
435 vl_compositor_render(cstate
, compositor
, surf
, dirty_area
, true);
437 pipe
->flush(pipe
, &surface_priv
->fence
, 0);
439 XVMC_MSG(XVMC_TRACE
, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface
);
441 pipe
->screen
->flush_frontbuffer
443 pipe
->screen
, tex
, 0, 0,
444 vl_screen_get_private(context_priv
->vscreen
)
447 if(dump_window
== -1) {
448 dump_window
= debug_get_num_option("XVMC_DUMP", 0);
452 static unsigned int framenum
= 0;
455 sprintf(cmd
, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable
, ++framenum
);
456 if (system(cmd
) != 0)
457 XVMC_MSG(XVMC_ERR
, "[XvMC] Dumping surface %p failed.\n", surface
);
460 XVMC_MSG(XVMC_TRACE
, "[XvMC] Pushed surface %p to front buffer.\n", surface
);
466 Status
XvMCGetSurfaceStatus(Display
*dpy
, XvMCSurface
*surface
, int *status
)
468 struct pipe_context
*pipe
;
469 XvMCSurfacePrivate
*surface_priv
;
470 XvMCContextPrivate
*context_priv
;
475 return XvMCBadSurface
;
479 surface_priv
= surface
->privData
;
480 context_priv
= surface_priv
->context
->privData
;
481 pipe
= context_priv
->pipe
;
485 if (surface_priv
->fence
)
486 if (!pipe
->screen
->fence_signalled(pipe
->screen
, surface_priv
->fence
))
487 *status
|= XVMC_RENDERING
;
493 Status
XvMCDestroySurface(Display
*dpy
, XvMCSurface
*surface
)
495 XvMCSurfacePrivate
*surface_priv
;
496 XvMCContextPrivate
*context_priv
;
498 XVMC_MSG(XVMC_TRACE
, "[XvMC] Destroying surface %p.\n", surface
);
502 if (!surface
|| !surface
->privData
)
503 return XvMCBadSurface
;
505 surface_priv
= surface
->privData
;
506 context_priv
= surface_priv
->context
->privData
;
508 if (surface_priv
->picture_structure
) {
509 struct pipe_mpeg12_picture_desc desc
;
510 GetPictureDescription(surface_priv
, &desc
);
511 context_priv
->decoder
->end_frame(context_priv
->decoder
, surface_priv
->video_buffer
, &desc
.base
);
513 surface_priv
->video_buffer
->destroy(surface_priv
->video_buffer
);
515 surface
->privData
= NULL
;
517 XVMC_MSG(XVMC_TRACE
, "[XvMC] Surface %p destroyed.\n", surface
);
523 Status
XvMCHideSurface(Display
*dpy
, XvMCSurface
*surface
)
527 if (!surface
|| !surface
->privData
)
528 return XvMCBadSurface
;
530 /* No op, only for overlaid rendering */