1 /*****************************************************************************
2 * xvmc.c : XVMC plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 1998-2001 VideoLAN
7 * Authors: Shane Harper <shanegh@optusnet.com.au>
8 * Vincent Seguin <seguin@via.ecp.fr>
9 * Samuel Hocevar <sam@zoy.org>
10 * David Kennedy <dkennedy@tinytoad.com>
11 * Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
38 #include <vlc_interface.h>
42 #ifdef HAVE_MACHINE_PARAM_H
44 # include <machine/param.h>
45 # include <sys/types.h> /* typedef ushort */
50 # include <netinet/in.h> /* BSD: struct in_addr */
54 # include <sys/shm.h> /* shmget(), shmctl() */
59 #include <X11/Xutil.h>
60 #include <X11/keysym.h>
62 # include <X11/extensions/XShm.h>
64 #ifdef DPMSINFO_IN_DPMS_H
65 # include <X11/extensions/dpms.h>
68 #include <X11/extensions/Xv.h>
69 #include <X11/extensions/Xvlib.h>
70 #include <X11/extensions/vldXvMC.h>
72 #include "../../codec/xvmc/accel_xvmc.h"
74 #include "../../codec/spudec/spudec.h"
77 /* picture structure */
79 #define BOTTOM_FIELD 2
80 #define FRAME_PICTURE 3
82 /* picture coding type */
88 /*****************************************************************************
90 *****************************************************************************/
91 extern int Activate ( vlc_object_t * );
92 extern void Deactivate ( vlc_object_t * );
94 /*****************************************************************************
96 *****************************************************************************/
97 #define ADAPTOR_TEXT N_("XVMC adaptor number")
98 #define ADAPTOR_LONGTEXT N_( \
99 "If you graphics card provides several adaptors, this option allows you " \
100 "to choose which one will be used (you shouldn't have to change this).")
102 #define DISPLAY_TEXT N_("X11 display name")
103 #define DISPLAY_LONGTEXT N_( \
104 "Specify the X11 hardware display you want to use. By default VLC will " \
105 "use the value of the DISPLAY environment variable.")
107 #define CHROMA_TEXT N_("XVimage chroma format")
108 #define CHROMA_LONGTEXT N_( \
109 "Force the XVideo renderer to use a specific chroma format instead of " \
110 "trying to improve performances by using the most efficient one.")
112 #define SHM_TEXT N_("Use shared memory")
113 #define SHM_LONGTEXT N_( \
114 "Use shared memory to communicate between VLC and the X server.")
116 #define MODE_TEXT N_("Deinterlace mode")
117 #define MODE_LONGTEXT N_("You can choose the default deinterlace mode")
119 #define CROP_TEXT N_("Crop")
120 #define CROP_LONGTEXT N_("You can choose the crop style to apply.")
123 set_shortname( "XVMC" )
124 add_string( "xvmc-display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, true )
125 add_integer( "xvmc-adaptor", -1, NULL, ADAPTOR_TEXT, ADAPTOR_LONGTEXT, true )
126 add_string( "xvmc-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true )
127 #ifdef HAVE_SYS_SHM_H
128 add_bool( "xvmc-shm", 1, NULL, SHM_TEXT, SHM_LONGTEXT, true )
130 add_string( "xvmc-deinterlace-mode", "bob", NULL, MODE_TEXT, MODE_LONGTEXT, false )
131 add_string( "xvmc-crop-style", "eq", NULL, CROP_TEXT, CROP_LONGTEXT, false )
133 set_description( N_("XVMC extension video output") )
134 set_capability( "video output", 10 )
135 set_callbacks( Activate, Deactivate )
138 /* following functions are local */
140 static const unsigned accel_priority[] = {
144 #define NUM_ACCEL_PRIORITY (sizeof(accel_priority)/sizeof(accel_priority[0]))
147 * Additional thread safety, since the plugin may decide to destroy a context
148 * while it's surfaces are still active in the video-out loop.
149 * When / If XvMC libs are reasonably thread-safe, the locks can be made
150 * more efficient by allowing multiple threads in that do not destroy
151 * the context or surfaces that may be active in other threads.
154 static void init_context_lock( context_lock_t *c )
156 pthread_cond_init(&c->cond,NULL);
157 pthread_mutex_init(&c->mutex,NULL);
161 void free_context_lock( context_lock_t *c )
163 pthread_mutex_destroy(&c->mutex);
164 pthread_cond_destroy(&c->cond);
167 void xvmc_context_reader_lock( context_lock_t *c )
169 pthread_mutex_lock(&c->mutex);
171 pthread_mutex_unlock(&c->mutex);
174 void xvmc_context_reader_unlock( context_lock_t *c )
176 pthread_mutex_lock(&c->mutex);
177 if (c->num_readers > 0) {
178 if (--(c->num_readers) == 0) {
179 pthread_cond_broadcast(&c->cond);
182 pthread_mutex_unlock(&c->mutex);
185 void xvmc_context_writer_lock( context_lock_t *c )
187 pthread_mutex_lock(&c->mutex);
188 while(c->num_readers) {
189 pthread_cond_wait( &c->cond, &c->mutex );
193 void xvmc_context_writer_unlock( context_lock_t *c )
195 pthread_mutex_unlock( &c->mutex );
198 void clear_xx44_palette( xx44_palette_t *p )
201 uint32_t *cluts = p->cluts;
202 int *ids = p->lookup_cache;
207 i = 2*OVL_PALETTE_SIZE;
213 static void init_xx44_palette( xx44_palette_t *p, unsigned num_entries )
215 p->size = (num_entries > XX44_PALETTE_SIZE) ?
216 XX44_PALETTE_SIZE : num_entries;
219 static void dispose_xx44_palette(xx44_palette_t *p)
225 static void colorToPalette( const uint32_t *icolor, unsigned char *palette_p,
226 unsigned num_xvmc_components, char *xvmc_components )
228 const clut_t *color = (const clut_t *) icolor;
231 for (i=0; i<num_xvmc_components; ++i)
233 switch(xvmc_components[i])
235 case 'V': *palette_p = color->cr; break;
236 case 'U': *palette_p = color->cb; break;
238 default: *palette_p = color->y; break;
245 void xx44_to_xvmc_palette( const xx44_palette_t *p,unsigned char *xvmc_palette,
246 unsigned first_xx44_entry, unsigned num_xx44_entries,
247 unsigned num_xvmc_components, char *xvmc_components )
250 const uint32_t *cluts = p->cluts + first_xx44_entry;
252 for( i=0; i<num_xx44_entries; ++i )
254 if( (cluts - p->cluts) < p->size )
256 colorToPalette( cluts++, xvmc_palette,
257 num_xvmc_components, xvmc_components );
258 xvmc_palette += num_xvmc_components;
263 static int xx44_paletteIndex( xx44_palette_t *p, int color, uint32_t clut )
266 uint32_t *cluts = p->cluts;
269 if( (tmp = p->lookup_cache[color]) >= 0 )
271 if (cluts[tmp] == clut)
274 for (i=0; i<p->max_used; ++i)
276 if (*cluts++ == clut) {
277 p->lookup_cache[color] = i;
278 return p->lookup_cache[color];
282 if( p->max_used == (p->size -1) )
284 //printf("video_out: Warning! Out of xx44 palette colors!\n");
287 p->cluts[p->max_used] = clut;
288 p->lookup_cache[color] = p->max_used++;
289 return p->lookup_cache[color];
292 static void memblend_xx44( uint8_t *mem, uint8_t val,
293 size_t size, uint8_t mask )
295 uint8_t masked_val = val & mask;
297 /* size_t is unsigned, therefore always positive
303 if( (*mem & mask) <= masked_val )
309 void blend_xx44( uint8_t *dst_img, subpicture_t *sub_img,
310 int dst_width, int dst_height, int dst_pitch,
311 xx44_palette_t *palette, int ia44 )
315 VLC_UNUSED(dst_width);
316 VLC_UNUSED(dst_height);
317 VLC_UNUSED(dst_pitch);
327 uint8_t norm_pixel,clip_pixel;
333 uint16_t *p_source = NULL;
337 src_width = sub_img->i_width;
338 src_height = sub_img->i_height;
339 x_off = sub_img->i_x;
340 y_off = sub_img->i_y;
341 alphamask = (ia44) ? 0x0F : 0xF0;
342 p_source = (uint16_t *)sub_img->p_sys->p_data;
344 dst_y = dst_img + dst_pitch*y_off + x_off;
346 if( (x_off + sub_img->i_width) <= dst_width )
347 clip_right = sub_img->i_width;
349 clip_right = dst_width - x_off;
351 if ((src_height + y_off) > dst_height)
352 src_height = dst_height - y_off;
354 for (y = 0; y < src_height; y++)
356 mask = !( (y < sub_img->p_sys->i_y_start) ||
357 (y >= sub_img->p_sys->i_y_end) );
360 for (x = 0; x < src_width;)
362 i_color = *p_source & 0x3;
363 i_len = *p_source++ >> 2;
365 if( (i_len > 0) && ((x+i_len) <= src_width) )
367 /* Get the RLE part, then draw the line */
368 uint32_t color = (sub_img->p_sys->pi_yuv[i_color][0] << 16) |
369 (sub_img->p_sys->pi_yuv[i_color][1] << 0) |
370 (sub_img->p_sys->pi_yuv[i_color][2] << 8);
372 norm_pixel = (uint8_t)(
373 (xx44_paletteIndex( palette,i_color, color ) << 4) |
374 (sub_img->p_sys->pi_alpha[i_color] & 0x0F) );
375 clip_pixel = (uint8_t)(
376 (xx44_paletteIndex( palette,i_color + OVL_PALETTE_SIZE,
377 sub_img->p_sys->pi_yuv[i_color][0] ) << 4) |
378 (sub_img->p_sys->pi_alpha[i_color] & 0x0F));
382 norm_pixel = ((norm_pixel & 0x0F) << 4) | ((norm_pixel & 0xF0) >> 4);
383 clip_pixel = ((clip_pixel & 0x0F) << 4) | ((clip_pixel & 0xF0) >> 4);
387 if( x < sub_img->p_sys->i_x_start )
389 if( (x + i_len) <= sub_img->p_sys->i_x_start )
391 memblend_xx44( dst, norm_pixel, i_len, alphamask );
396 memblend_xx44( dst, norm_pixel,
397 sub_img->p_sys->i_x_start - x,
399 dst += sub_img->p_sys->i_x_start - x;
400 i_len -= sub_img->p_sys->i_x_start - x;
401 if( i_len <= (sub_img->p_sys->i_x_end -
402 sub_img->p_sys->i_x_start) )
404 memblend_xx44( dst, clip_pixel,
410 memblend_xx44( dst, clip_pixel,
411 sub_img->p_sys->i_x_end -
412 sub_img->p_sys->i_x_start,
414 dst += (sub_img->p_sys->i_x_end -
415 sub_img->p_sys->i_x_start);
416 i_len -= (sub_img->p_sys->i_x_end -
417 sub_img->p_sys->i_x_start);
418 memblend_xx44( dst, norm_pixel,
424 else if( x < sub_img->p_sys->i_x_end )
426 if( i_len <= (sub_img->p_sys->i_x_end - x) )
428 memblend_xx44( dst, clip_pixel, i_len, alphamask);
433 memblend_xx44( dst, clip_pixel,
434 sub_img->p_sys->i_x_end - x,
436 dst += (sub_img->p_sys->i_x_end - x);
437 i_len -= (sub_img->p_sys->i_x_end - x);
438 memblend_xx44( dst, norm_pixel, i_len, alphamask);
444 memblend_xx44( dst, norm_pixel, i_len, alphamask );
450 memblend_xx44( dst, norm_pixel, i_len, alphamask );
465 int xxmc_xvmc_surface_valid( vout_thread_t *p_vout, XvMCSurface *surf )
467 xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
468 unsigned long index = surf - handler->surfaces;
471 if( index >= XVMC_MAX_SURFACES )
473 pthread_mutex_lock(&handler->mutex);
474 ret = handler->surfValid[index];
475 pthread_mutex_unlock(&handler->mutex);
479 static void xxmc_xvmc_dump_subpictures( vout_thread_t *p_vout )
482 xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
484 for( i=0; i < XVMC_MAX_SUBPICTURES; ++i )
486 msg_Dbg( p_vout, "handler in use %d, valid %d",
487 handler->subInUse[i],
488 handler->subValid[i]);
492 XvMCSubpicture *xxmc_xvmc_alloc_subpicture( vout_thread_t *p_vout,
493 XvMCContext *context, unsigned short width,
494 unsigned short height, int xvimage_id )
497 xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
500 pthread_mutex_lock(&handler->mutex);
501 /* xxmc_xvmc_dump_subpictures(p_vout); */
502 for( i=0; i<XVMC_MAX_SUBPICTURES; ++i )
504 if( handler->subValid[i] && !handler->subInUse[i] )
506 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
507 if( XvMCGetSubpictureStatus( p_vout->p_sys->p_display,
508 handler->subpictures + i,
511 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
514 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
515 if( status & XVMC_DISPLAYING )
517 handler->subInUse[i] = 1;
518 /* xxmc_xvmc_dump_subpictures(p_vout); */
519 pthread_mutex_unlock(&handler->mutex);
520 return (handler->subpictures + i);
523 for (i=0; i<XVMC_MAX_SUBPICTURES; ++i)
525 if( !handler->subInUse[i] )
527 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
528 if( Success != XvMCCreateSubpicture( p_vout->p_sys->p_display,
530 handler->subpictures + i,
531 width, height, xvimage_id ) )
533 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
534 pthread_mutex_unlock( &handler->mutex );
537 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
538 msg_Dbg( p_vout, "video_out_xxmc: created subpicture %d", i );
539 handler->subInUse[i] = 1;
540 handler->subValid[i] = 1;
541 pthread_mutex_unlock( &handler->mutex );
542 return (handler->subpictures + i);
545 pthread_mutex_unlock( &handler->mutex );
549 void xxmc_xvmc_free_subpicture( vout_thread_t *p_vout, XvMCSubpicture *sub )
551 xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
552 unsigned int index = sub - handler->subpictures;
554 if( index >= XVMC_MAX_SUBPICTURES )
557 pthread_mutex_lock( &handler->mutex );
558 handler->subInUse[index] = 0;
559 /* xxmc_xvmc_dump_subpictures(p_vout); */
560 pthread_mutex_unlock( &handler->mutex );
563 static void xxmc_xvmc_surface_handler_construct( vout_thread_t *p_vout )
566 xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
568 pthread_mutex_init( &handler->mutex, NULL );
569 for( i=0; i<XVMC_MAX_SURFACES; ++i )
571 handler->surfInUse[i] = 0;
572 handler->surfValid[i] = 0;
574 for( i=0; i<XVMC_MAX_SUBPICTURES; ++i )
576 handler->subInUse[i] = 0;
577 handler->subValid[i] = 0;
581 static void xxmc_xvmc_dump_surfaces( vout_thread_t *p_vout )
584 xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
586 for (i=0; i<XVMC_MAX_SURFACES; ++i)
588 msg_Dbg(p_vout, "surfaces in use %d, valid %d;",
589 handler->surfInUse[i],
590 handler->surfValid[i]);
594 void xxmc_xvmc_free_surface( vout_thread_t *p_vout, XvMCSurface *surf )
596 xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
597 unsigned int index = 0;
599 index = (surf - handler->surfaces);
601 if (index < XVMC_MAX_SURFACES)
603 pthread_mutex_lock(&handler->mutex);
604 msg_Dbg( p_vout,"free surface %d",index );
605 handler->surfInUse[index]--;
606 xxmc_xvmc_dump_surfaces(p_vout);
607 pthread_mutex_unlock(&handler->mutex);
611 int checkXvMCCap( vout_thread_t *p_vout )
617 XvMCSurfaceInfo *surfaceInfo =NULL;
618 XvMCSurfaceInfo *curInfo = NULL;
620 xvmc_capabilities_t *curCap = NULL;
621 XvImageFormatValues *formatValues = NULL;
623 i_xvport = p_vout->p_sys->i_xvport;
624 p_vout->p_sys->xvmc_cap = 0;
626 init_context_lock( &p_vout->p_sys->xvmc_lock );
627 xvmc_context_writer_lock( &p_vout->p_sys->xvmc_lock );
629 p_vout->p_sys->old_subpic = NULL;
630 p_vout->p_sys->new_subpic = NULL;
631 p_vout->p_sys->contextActive = 0;
632 p_vout->p_sys->subImage = NULL;
633 p_vout->p_sys->hwSubpictures = 0;
634 p_vout->p_sys->xvmc_palette = NULL;
636 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
638 if( !XvMCQueryExtension( p_vout->p_sys->p_display,
639 &p_vout->p_sys->xvmc_eventbase,
640 &p_vout->p_sys->xvmc_errbase ) )
642 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
643 xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
646 msg_Dbg( p_vout,"XvMC extension found" );
648 surfaceInfo = XvMCListSurfaceTypes(p_vout->p_sys->p_display, i_xvport, &numSurf);
651 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
652 xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
656 p_vout->p_sys->xvmc_cap =
657 (xvmc_capabilities_t *) malloc( numSurf *
658 sizeof(xvmc_capabilities_t) );
659 if( !p_vout->p_sys->xvmc_cap )
661 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
662 xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
666 p_vout->p_sys->xvmc_num_cap = numSurf;
667 curInfo = surfaceInfo;
668 curCap = p_vout->p_sys->xvmc_cap;
670 msg_Dbg( p_vout,"found %d XvMC surface types", numSurf );
672 for( i=0; i< numSurf; ++i )
674 curCap->mpeg_flags = 0;
675 curCap->accel_flags = 0;
676 if( curInfo->chroma_format == XVMC_CHROMA_FORMAT_420 )
678 curCap->mpeg_flags |= ((curInfo->mc_type & XVMC_MPEG_1) ?
679 VLC_XVMC_MPEG_1 : 0);
680 curCap->mpeg_flags |= ((curInfo->mc_type & XVMC_MPEG_2) ?
681 VLC_XVMC_MPEG_2 : 0);
682 curCap->mpeg_flags |= ((curInfo->mc_type & XVMC_MPEG_4) ?
683 VLC_XVMC_MPEG_4 : 0);
684 curCap->accel_flags |= ((curInfo->mc_type & XVMC_VLD) ?
685 VLC_XVMC_ACCEL_VLD : 0);
686 curCap->accel_flags |= ((curInfo->mc_type & XVMC_IDCT) ?
687 VLC_XVMC_ACCEL_IDCT : 0);
688 curCap->accel_flags |= ((curInfo->mc_type & (XVMC_VLD | XVMC_IDCT)) ?
689 0 : VLC_XVMC_ACCEL_MOCOMP);
690 curCap->max_width = curInfo->max_width;
691 curCap->max_height = curInfo->max_height;
692 curCap->sub_max_width = curInfo->subpicture_max_width;
693 curCap->sub_max_height = curInfo->subpicture_max_height;
694 curCap->flags = curInfo->flags;
696 msg_Dbg (p_vout, "surface type %d: Max size: %d %d.",
697 i, curCap->max_width, curCap->max_height);
698 msg_Dbg (p_vout, "surface subtype %d: Max subpic size: %d %d.",
699 i, curCap->sub_max_width, curCap->sub_max_height);
701 curCap->type_id = curInfo->surface_type_id;
702 formatValues = XvMCListSubpictureTypes( p_vout->p_sys->p_display,
706 curCap->subPicType.id = 0;
709 msg_Dbg( p_vout, "surface type %d: found %d XvMC subpicture types",
711 for( j = 0; j<numSub; ++j )
713 if( formatValues[j].id == FOURCC_IA44 )
715 curCap->subPicType = formatValues[j];
717 "surface type %d: detected and using "
718 "IA44 subpicture type.", i );
722 else if( formatValues[j].id == FOURCC_AI44 )
724 curCap->subPicType = formatValues[j];
726 "surface type %d: detected AI44 "
727 "subpicture type.", i );
739 * Try to create a direct rendering context. This will fail if we are not
740 * on the displaying computer or an indirect context is not available.
742 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
743 curCap = p_vout->p_sys->xvmc_cap;
744 if( Success == XvMCCreateContext( p_vout->p_sys->p_display, i_xvport,
750 msg_Dbg( p_vout, "using direct XVMC rendering context" );
751 p_vout->p_sys->context_flags = XVMC_DIRECT;
753 else if( Success == XvMCCreateContext( p_vout->p_sys->p_display, i_xvport,
759 msg_Dbg( p_vout, "using default XVMC rendering context" );
760 p_vout->p_sys->context_flags = 0;
764 free( p_vout->p_sys->xvmc_cap );
765 p_vout->p_sys->xvmc_cap = NULL;
766 msg_Err( p_vout, "use of direct XvMC context on a remote display failed"
767 " falling back to XV." );
768 xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
771 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
772 XvMCDestroyContext( p_vout->p_sys->p_display, &c );
773 xxmc_xvmc_surface_handler_construct( p_vout );
774 /* p_vout->p_sys->capabilities |= VO_CAP_XXMC; */
775 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
776 init_xx44_palette( &p_vout->p_sys->palette , 0 );
777 p_vout->p_sys->last_accel_request = 0xFFFFFFFF;
778 xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
782 static int xxmc_setup_subpictures( vout_thread_t *p_vout,
783 unsigned int width, unsigned int height )
785 xvmc_capabilities_t *curCap = NULL;
786 XvMCSubpicture *sp = NULL;
788 if( p_vout->p_sys->contextActive )
790 curCap = p_vout->p_sys->xvmc_cap + p_vout->p_sys->xvmc_cur_cap;
792 if( (width > curCap->sub_max_width) ||
793 (height > curCap->sub_max_height) )
796 if( (p_vout->p_sys->xvmc_backend_subpic =
797 (curCap->flags & XVMC_BACKEND_SUBPICTURE)) )
798 msg_Dbg( p_vout, "using backend subpictures." );
800 if (!p_vout->p_sys->subImage)
802 XLockDisplay( p_vout->p_sys->p_display );
803 msg_Dbg(p_vout, "xxmc_setup_subpictures");
804 #ifdef HAVE_SYS_SHM_H
805 if( p_vout->p_sys->i_shm_opcode )
807 /* Create image using XShm extension */
808 p_vout->p_sys->subImage = CreateShmImage( p_vout,
809 p_vout->p_sys->p_display,
810 p_vout->p_sys->i_xvport,
811 curCap->subPicType.id,
812 /* VLC2X11_FOURCC( p_vout->output. i_chroma ), */
813 &p_vout->p_sys->subShmInfo,
814 p_vout->output.i_width,
815 p_vout->output.i_height );
817 #endif /* HAVE_SYS_SHM_H */
818 XUnlockDisplay( p_vout->p_sys->p_display );
819 if( !p_vout->p_sys->subImage )
821 msg_Dbg(p_vout, "failed allocating XvImage for supbictures" );
826 sp = xxmc_xvmc_alloc_subpicture( p_vout, &p_vout->p_sys->context,
828 curCap->subPicType.id );
831 init_xx44_palette( &p_vout->p_sys->palette, sp->num_palette_entries );
832 p_vout->p_sys->xvmc_palette = (char *) malloc( sp->num_palette_entries
834 xxmc_xvmc_free_subpicture( p_vout, sp);
835 if( !p_vout->p_sys->xvmc_palette )
837 p_vout->p_sys->hwSubpictures = 1;
843 static void xvmc_check_colorkey_properties( vout_thread_t *p_vout )
846 XvAttribute *xvmc_attributes = NULL;
850 * Determine if the context is of "Overlay" type. If so,
851 * check whether we can autopaint.
853 p_vout->p_sys->have_xvmc_autopaint = 0;
854 if( p_vout->p_sys->context_flags & XVMC_OVERLAID_SURFACE )
856 msg_Dbg( p_vout, "check colorkey properties" );
857 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
858 xvmc_attributes = XvMCQueryAttributes( p_vout->p_sys->p_display,
859 &p_vout->p_sys->context,
861 if( xvmc_attributes )
863 for( i = 0; i < num; ++i )
865 if( strncmp( "XV_AUTOPAINT_COLORKEY",
866 xvmc_attributes[i].name,
869 ap = XInternAtom( p_vout->p_sys->p_display,
870 "XV_AUTOPAINT_COLORKEY",
872 XvMCSetAttribute( p_vout->p_sys->p_display,
873 &p_vout->p_sys->context,
875 1 ); /* p_vout->p_sys->props[VO_PROP_AUTOPAINT_COLORKEY].value */
876 p_vout->p_sys->have_xvmc_autopaint = 1;
877 msg_Dbg( p_vout, "has xvmc autopaint" );
881 XFree( xvmc_attributes );
882 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
883 /* p_vout->p_sys->xvmc_xoverlay_type = X11OSD_COLORKEY; */
888 p_vout->p_sys->xvmc_xoverlay_type = X11OSD_SHAPED;
893 static void xxmc_xvmc_destroy_surfaces( vout_thread_t *p_vout )
896 xvmc_surface_handler_t *handler = NULL;
898 handler = &p_vout->p_sys->xvmc_surf_handler;
900 pthread_mutex_lock( &handler->mutex );
901 for( i = 0; i < XVMC_MAX_SURFACES; ++i )
903 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
904 if( handler->surfValid[i] )
906 XvMCFlushSurface( p_vout->p_sys->p_display , handler->surfaces+i);
907 XvMCSyncSurface( p_vout->p_sys->p_display, handler->surfaces+i );
908 XvMCHideSurface( p_vout->p_sys->p_display, handler->surfaces+i );
909 XvMCDestroySurface( p_vout->p_sys->p_display, handler->surfaces+i );
911 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
912 handler->surfValid[i] = 0;
914 pthread_mutex_unlock( &handler->mutex );
917 static void xxmc_xvmc_destroy_subpictures( vout_thread_t *p_vout )
920 xvmc_surface_handler_t *handler = NULL;
922 handler = &p_vout->p_sys->xvmc_surf_handler;
924 pthread_mutex_lock( &handler->mutex );
925 for( i = 0; i < XVMC_MAX_SUBPICTURES; ++i )
927 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
928 if( handler->subValid[i] )
930 XvMCFlushSubpicture( p_vout->p_sys->p_display , handler->subpictures+i);
931 XvMCSyncSubpicture( p_vout->p_sys->p_display, handler->subpictures+i );
932 XvMCDestroySubpicture( p_vout->p_sys->p_display, handler->subpictures+i );
934 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
935 handler->subValid[i] = 0;
937 pthread_mutex_unlock( &handler->mutex );
940 static XvMCSurface *xxmc_xvmc_alloc_surface( vout_thread_t *p_vout,
941 XvMCContext *context )
943 xvmc_surface_handler_t *handler = NULL;
946 handler = &p_vout->p_sys->xvmc_surf_handler;
948 pthread_mutex_lock( &handler->mutex );
949 xxmc_xvmc_dump_surfaces( p_vout );
950 for( i = 0; i < XVMC_MAX_SURFACES; ++i )
952 if( handler->surfValid[i] && !handler->surfInUse[i] )
954 handler->surfInUse[i] = 1;
955 msg_Dbg( p_vout, "reusing surface %d", i );
956 xxmc_xvmc_dump_surfaces( p_vout );
957 pthread_mutex_unlock( &handler->mutex );
958 return (handler->surfaces + i);
961 for( i = 0; i < XVMC_MAX_SURFACES; ++i )
963 if( !handler->surfInUse[i] )
965 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
966 if( Success != XvMCCreateSurface( p_vout->p_sys->p_display,
968 handler->surfaces + i) )
970 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
971 pthread_mutex_unlock( &handler->mutex );
974 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
976 msg_Dbg( p_vout, "created surface %d", i );
977 handler->surfInUse[i] = 1;
978 handler->surfValid[i] = 1;
979 pthread_mutex_unlock( &handler->mutex );
980 return (handler->surfaces + i);
983 pthread_mutex_unlock( &handler->mutex );
987 void xxmc_dispose_context( vout_thread_t *p_vout )
989 if( p_vout->p_sys->contextActive )
991 if( p_vout->p_sys->xvmc_accel &
992 (VLC_XVMC_ACCEL_MOCOMP | VLC_XVMC_ACCEL_IDCT) )
994 xvmc_macroblocks_t *macroblocks = NULL;
996 macroblocks = &p_vout->p_sys->macroblocks;
997 XvMCDestroyMacroBlocks( p_vout->p_sys->p_display,
998 ¯oblocks->macro_blocks );
999 XvMCDestroyBlocks( p_vout->p_sys->p_display,
1000 ¯oblocks->blocks );
1003 msg_Dbg( p_vout, "freeing up XvMC surfaces and subpictures" );
1004 free( p_vout->p_sys->xvmc_palette );
1005 dispose_xx44_palette( &p_vout->p_sys->palette );
1006 xxmc_xvmc_destroy_subpictures( p_vout );
1007 xxmc_xvmc_destroy_surfaces( p_vout );
1009 msg_Dbg(p_vout, "freeing up XvMC Context.");
1010 XLockDisplay( p_vout->p_sys->p_display );
1011 if( p_vout->p_sys->subImage )
1013 XFree( p_vout->p_sys->subImage );
1014 p_vout->p_sys->subImage = NULL;
1016 p_vout->p_sys->subImage = NULL;
1017 XUnlockDisplay( p_vout->p_sys->p_display );
1018 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
1019 XvMCDestroyContext( p_vout->p_sys->p_display,
1020 &p_vout->p_sys->context );
1021 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1022 p_vout->p_sys->contextActive = 0;
1023 p_vout->p_sys->hwSubpictures = 0;
1024 p_vout->p_sys->xvmc_accel = 0;
1028 static int xxmc_find_context( vout_thread_t *p_vout, vlc_xxmc_t *xxmc,
1029 unsigned int width, unsigned int height )
1033 xvmc_capabilities_t *curCap = NULL;
1034 unsigned int request_mpeg_flags, request_accel_flags;
1036 request_mpeg_flags = xxmc->mpeg;
1037 for( k = 0; k < NUM_ACCEL_PRIORITY; ++k )
1039 request_accel_flags = xxmc->acceleration & accel_priority[k];
1040 if( !request_accel_flags )
1043 curCap = p_vout->p_sys->xvmc_cap;
1044 for( i =0; i < p_vout->p_sys->xvmc_num_cap; ++i )
1046 msg_Dbg( p_vout, "surface type %d, capabilities 0x%8x 0x%8x",
1049 curCap->accel_flags );
1050 msg_Dbg( p_vout, "fequests: 0x%8x 0x%8x",
1052 request_accel_flags );
1053 if( ( (curCap->mpeg_flags & request_mpeg_flags) == request_mpeg_flags) &&
1054 (curCap->accel_flags & request_accel_flags) &&
1055 (width <= curCap->max_width) &&
1056 (height <= curCap->max_height) )
1065 p_vout->p_sys->xvmc_cur_cap = i;
1071 p_vout->p_sys->xvmc_accel = request_accel_flags;
1072 p_vout->p_sys->unsigned_intra = (curCap->flags & XVMC_INTRA_UNSIGNED);
1075 p_vout->p_sys->xvmc_accel = 0;
1079 static int xxmc_create_context( vout_thread_t *p_vout,
1080 unsigned int width, unsigned int height )
1082 xvmc_capabilities_t *curCap = NULL;
1084 curCap = p_vout->p_sys->xvmc_cap + p_vout->p_sys->xvmc_cur_cap;
1086 msg_Dbg( p_vout, "creating new XvMC context %d", curCap->type_id );
1088 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
1089 if( Success == XvMCCreateContext( p_vout->p_sys->p_display,
1090 p_vout->p_sys->i_xvport,
1094 p_vout->p_sys->context_flags,
1095 &p_vout->p_sys->context ) )
1097 p_vout->p_sys->xvmc_mpeg = curCap->mpeg_flags;
1098 p_vout->p_sys->xvmc_width = width;
1099 p_vout->p_sys->xvmc_height = height;
1100 p_vout->p_sys->contextActive = 1;
1102 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1103 return p_vout->p_sys->contextActive;
1106 static void xvmc_flushsync(picture_t *picture)
1108 vout_thread_t *p_vout = picture->p_sys->p_vout;
1110 xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
1112 if( !xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf ) )
1114 msg_Dbg(p_vout, "xvmc_flushsync 1 : %d", picture->p_sys->xxmc_data.result );
1115 picture->p_sys->xxmc_data.result = 128;
1116 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1120 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
1121 picture->p_sys->xxmc_data.result =
1122 XvMCFlushSurface( p_vout->p_sys->p_display,
1123 picture->p_sys->xvmc_surf );
1124 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1125 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1128 static void xvmc_flush(picture_t *picture)
1130 vout_thread_t *p_vout = picture->p_sys->p_vout;
1132 xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
1134 if ( !xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf ) )
1136 msg_Dbg(p_vout, "xvmc flush 1 : %d", picture->p_sys->xxmc_data.result );
1137 picture->p_sys->xxmc_data.result = 128;
1138 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1142 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
1143 picture->p_sys->xxmc_data.result =
1144 XvMCFlushSurface( p_vout->p_sys->p_display,
1145 picture->p_sys->xvmc_surf );
1146 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1147 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1150 static int xxmc_frame_updates( vout_thread_t *p_vout, picture_t *picture )
1152 vlc_xxmc_t *xxmc = &picture->p_sys->xxmc_data;
1155 * If we have changed context since the surface was updated, xvmc_surf
1156 * is either NULL or invalid. If it is invalid. Set it to NULL.
1157 * Also if there are other users of this surface, deregister our use of
1158 * it and later try to allocate a new, fresh one.
1161 if( picture->p_sys->xvmc_surf )
1163 if( !xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf ) )
1165 xxmc_xvmc_free_surface( p_vout , picture->p_sys->xvmc_surf );
1166 picture->p_sys->xvmc_surf = NULL;
1170 if( picture->p_sys->p_image )
1172 memset( picture->p_sys->p_image->data, 0,
1173 picture->p_sys->p_image->width
1174 * picture->p_sys->p_image->height );
1178 * If it is NULL create a new surface.
1180 if( !picture->p_sys->xvmc_surf )
1182 picture->p_sys->xvmc_surf = xxmc_xvmc_alloc_surface( p_vout,
1183 &p_vout->p_sys->context );
1184 if( !picture->p_sys->xvmc_surf )
1186 msg_Err( p_vout, "accelerated surface allocation failed.\n"
1187 " You are probably out of framebuffer memory.\n"
1188 " Falling back to software decoding." );
1189 p_vout->p_sys->xvmc_accel = 0;
1190 xxmc_dispose_context( p_vout );
1191 return VLC_EGENERIC;
1194 xxmc->acceleration = p_vout->p_sys->xvmc_accel;
1196 xxmc->proc_xxmc_flush = xvmc_flush;
1197 xxmc->proc_xxmc_flushsync = xvmc_flushsync;
1198 xxmc->xvmc.proc_macro_block = NULL;
1200 frame->vo_frame.proc_duplicate_frame_data = xxmc_duplicate_frame_data;
1202 xxmc->proc_xxmc_begin = xvmc_vld_frame;
1203 xxmc->proc_xxmc_slice = xvmc_vld_slice;
1207 static int xxmc_xvmc_update_context( vout_thread_t *p_vout,
1208 picture_t *picture, uint32_t width, uint32_t height )
1210 vlc_xxmc_t *xxmc = &picture->p_sys->xxmc_data;
1213 * Are we at all capable of doing XvMC ?
1215 if( p_vout->p_sys->xvmc_cap == 0 )
1216 return VLC_EGENERIC;
1218 msg_Dbg( p_vout, "new format: need to change XvMC context. "
1219 "width: %d height: %d mpeg: %d acceleration: %d",
1221 xxmc->mpeg, xxmc->acceleration );
1223 if( picture->p_sys->xvmc_surf )
1224 xxmc_xvmc_free_surface( p_vout , picture->p_sys->xvmc_surf );
1225 picture->p_sys->xvmc_surf = NULL;
1227 xxmc_dispose_context( p_vout );
1229 if( xxmc_find_context( p_vout, xxmc, width, height ) )
1231 xxmc_create_context( p_vout, width, height);
1232 xvmc_check_colorkey_properties( p_vout );
1233 xxmc_setup_subpictures(p_vout, width, height);
1236 if( !p_vout->p_sys->contextActive )
1238 msg_Dbg( p_vout, "using software decoding for this stream" );
1239 p_vout->p_sys->xvmc_accel = 0;
1243 msg_Dbg(p_vout, "using hardware decoding for this stream." );
1246 p_vout->p_sys->xvmc_mpeg = xxmc->mpeg;
1247 p_vout->p_sys->xvmc_width = width;
1248 p_vout->p_sys->xvmc_height = height;
1249 return p_vout->p_sys->contextActive;
1253 void xxmc_do_update_frame( picture_t *picture, uint32_t width, uint32_t height,
1254 double ratio, int format, int flags)
1258 vout_thread_t *p_vout = picture->p_sys->p_vout;
1262 picture->p_sys->xxmc_data.decoded = 0;
1263 picture->p_sys->nb_display = 0;
1264 picture->b_force = 0;
1265 vlc_xxmc_t *xxmc = &picture->p_sys->xxmc_data;
1267 xvmc_context_writer_lock( &p_vout->p_sys->xvmc_lock);
1268 if( (p_vout->p_sys->last_accel_request != xxmc->acceleration) ||
1269 (p_vout->p_sys->xvmc_mpeg != xxmc->mpeg) ||
1270 (p_vout->p_sys->xvmc_width != width) ||
1271 (p_vout->p_sys->xvmc_height != height))
1273 p_vout->p_sys->last_accel_request = xxmc->acceleration;
1274 xxmc_xvmc_update_context( p_vout, picture, width, height );
1277 if( p_vout->p_sys->contextActive )
1278 xxmc_frame_updates( p_vout, picture );
1280 if( !p_vout->p_sys->contextActive )
1282 xxmc->acceleration = 0;
1283 xxmc->xvmc.macroblocks = 0;
1287 picture->format.i_chroma = format;
1289 xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock);
1291 XvMCGetSurfaceStatus( p_vout->p_sys->p_display,
1292 picture->p_sys->xvmc_surf,
1294 /* Wait a little till frame is being displayed */
1295 while( status & XVMC_DISPLAYING )
1299 XvMCGetSurfaceStatus( p_vout->p_sys->p_display,
1300 picture->p_sys->xvmc_surf,
1310 /* called xlocked */
1311 static void dispose_ximage( vout_thread_t *p_vout, XShmSegmentInfo *shminfo,
1314 # ifdef HAVE_SYS_SHM_H
1315 if( p_vout->p_sys->i_shm_opcode )
1317 XShmDetach( p_vout->p_sys->p_display, shminfo );
1319 shmdt( shminfo->shmaddr );
1320 if( shminfo->shmid >= 0 )
1322 shmctl( shminfo->shmid, IPC_RMID, 0 );
1323 shminfo->shmid = -1;
1330 free(myimage->data);
1336 void xvmc_vld_frame( picture_t *picture )
1338 picture_sys_t *p_sys = picture->p_sys;
1339 vout_thread_t *p_vout = p_sys->p_vout;
1340 vlc_vld_frame_t *vft = &(p_sys->xxmc_data.vld_frame);
1341 picture_t *ff = (picture_t *) vft->forward_reference_picture;
1342 picture_t *bf = (picture_t *) vft->backward_reference_picture;
1343 XvMCMpegControl ctl;
1344 XvMCSurface *fs=0, *bs=0;
1347 ctl.BHMV_range = vft->mv_ranges[0][0];
1348 ctl.BVMV_range = vft->mv_ranges[0][1];
1349 ctl.FHMV_range = vft->mv_ranges[1][0];
1350 ctl.FVMV_range = vft->mv_ranges[1][1];
1351 ctl.picture_structure = vft->picture_structure;
1352 ctl.intra_dc_precision = vft->intra_dc_precision;
1353 ctl.picture_coding_type = vft->picture_coding_type;
1354 ctl.mpeg_coding = (vft->mpeg_coding == 0) ? XVMC_MPEG_1 : XVMC_MPEG_2;
1356 ctl.flags |= (vft->progressive_sequence) ? XVMC_PROGRESSIVE_SEQUENCE : 0;
1357 ctl.flags |= (vft->scan) ? XVMC_ALTERNATE_SCAN : XVMC_ZIG_ZAG_SCAN;
1358 ctl.flags |= (vft->pred_dct_frame) ?
1359 XVMC_PRED_DCT_FRAME : XVMC_PRED_DCT_FIELD;
1360 ctl.flags |= (picture->b_top_field_first) ?
1361 XVMC_TOP_FIELD_FIRST : XVMC_BOTTOM_FIELD_FIRST;
1362 ctl.flags |= (vft->concealment_motion_vectors) ?
1363 XVMC_CONCEALMENT_MOTION_VECTORS : 0;
1364 ctl.flags |= (vft->q_scale_type) ? XVMC_Q_SCALE_TYPE : 0;
1365 ctl.flags |= (vft->intra_vlc_format) ? XVMC_INTRA_VLC_FORMAT : 0;
1366 ctl.flags |= (vft->second_field) ? XVMC_SECOND_FIELD : 0;
1369 fs = ff->p_sys->xvmc_surf;
1371 bs = bf->p_sys->xvmc_surf;
1374 * Below is for interlaced streams and second_field.
1376 if( ctl.picture_coding_type == P_TYPE ) /* XVMC_P_PICTURE) */
1377 bs = picture->p_sys->xvmc_surf;
1379 if( (qmx.load_intra_quantiser_matrix = vft->load_intra_quantizer_matrix) )
1381 memcpy( qmx.intra_quantiser_matrix, vft->intra_quantizer_matrix,
1382 sizeof(qmx.intra_quantiser_matrix) );
1384 if( (qmx.load_non_intra_quantiser_matrix =
1385 vft->load_non_intra_quantizer_matrix) )
1387 memcpy( qmx.non_intra_quantiser_matrix, vft->non_intra_quantizer_matrix,
1388 sizeof(qmx.non_intra_quantiser_matrix) );
1390 qmx.load_chroma_intra_quantiser_matrix = 0;
1391 qmx.load_chroma_non_intra_quantiser_matrix = 0;
1392 xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
1394 if( !xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf ) )
1396 picture->p_sys->xxmc_data.result = 128;
1397 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1401 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
1402 XvMCLoadQMatrix( p_vout->p_sys->p_display, &p_vout->p_sys->context, &qmx );
1404 picture->p_sys->xxmc_data.result =
1405 XvMCBeginSurface( p_vout->p_sys->p_display,
1406 &p_vout->p_sys->context,
1407 picture->p_sys->xvmc_surf,
1409 } while( !picture->p_sys->xxmc_data.result );
1410 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1411 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1414 void xvmc_vld_slice( picture_t *picture )
1416 picture_sys_t *p_sys = picture->p_sys;
1417 vout_thread_t *p_vout = p_sys->p_vout;
1419 xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
1420 if( !xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf ) )
1422 picture->p_sys->xxmc_data.result = 128;
1423 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1424 msg_Err(p_vout, "vld slice error" );
1428 XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
1429 picture->p_sys->xxmc_data.result =
1430 XvMCPutSlice2( p_vout->p_sys->p_display,
1431 &p_vout->p_sys->context,
1432 (char *)picture->p_sys->xxmc_data.slice_data,
1433 picture->p_sys->xxmc_data.slice_data_size,
1434 picture->p_sys->xxmc_data.slice_code );
1436 if( picture->p_sys->xxmc_data.result != 0 )
1437 msg_Err( p_vout, "vlc slice error %d",
1438 picture->p_sys->xxmc_data.result );
1440 * If CPU-saving mode is enabled, sleep after every xxmc->sleep slice. This will free
1441 * up the cpu while the decoder is working on the slice. The value of xxmc->sleep is calculated
1442 * so that the decoder thread sleeps at most 50% of the frame delay,
1443 * assuming a 2.6 kernel clock of 1000 Hz.
1445 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1446 xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1448 if( p_vout->p_sys->cpu_save_enabled )
1450 p_vout->p_sys->cpu_saver += 1.;
1451 if( p_vout->p_sys->cpu_saver >= picture->p_sys->xxmc_data.sleep )
1454 p_vout->p_sys->cpu_saver -= picture->p_sys->xxmc_data.sleep;