]> git.sesse.net Git - vlc/blob - modules/video_output/x11/xvmc.c
d19ed247a2ee09022b77373ebb18552f285b1b3a
[vlc] / modules / video_output / x11 / xvmc.c
1 /*****************************************************************************
2  * xvmc.c : XVMC plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 1998-2001 VideoLAN
5  * $Id$
6  *
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>
12  *
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.
17  *
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.
22  *
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  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <vlc/vlc.h>
37 #include <vlc_interface.h>
38 #include <vlc_vout.h>
39 #include <vlc_keys.h>
40
41 #ifdef HAVE_MACHINE_PARAM_H
42     /* BSD */
43 #   include <machine/param.h>
44 #   include <sys/types.h>                                  /* typedef ushort */
45 #   include <sys/ipc.h>
46 #endif
47
48 #ifndef WIN32
49 #   include <netinet/in.h>                            /* BSD: struct in_addr */
50 #endif
51
52 #ifdef HAVE_SYS_SHM_H
53 #   include <sys/shm.h>                                /* shmget(), shmctl() */
54 #endif
55
56 #include <X11/Xlib.h>
57 #include <X11/Xmd.h>
58 #include <X11/Xutil.h>
59 #include <X11/keysym.h>
60 #ifdef HAVE_SYS_SHM_H
61 #   include <X11/extensions/XShm.h>
62 #endif
63 #ifdef DPMSINFO_IN_DPMS_H
64 #   include <X11/extensions/dpms.h>
65 #endif
66
67 #include <X11/extensions/Xv.h>
68 #include <X11/extensions/Xvlib.h>
69 #include <X11/extensions/vldXvMC.h>
70
71 #include "../../codec/xxmc/accel_xvmc.h"
72 #include "xcommon.h"
73 #include "../../codec/spudec/spudec.h"
74 #include <unistd.h>
75
76 /* picture structure */
77 #define TOP_FIELD 1
78 #define BOTTOM_FIELD 2
79 #define FRAME_PICTURE 3
80
81 /* picture coding type */
82 #define I_TYPE 1
83 #define P_TYPE 2
84 #define B_TYPE 3
85 #define D_TYPE 4
86
87 /*****************************************************************************
88  * Exported prototypes
89  *****************************************************************************/
90 extern int  E_(Activate)   ( vlc_object_t * );
91 extern void E_(Deactivate) ( vlc_object_t * );
92
93 /*****************************************************************************
94  * Module descriptor
95  *****************************************************************************/
96 #define ADAPTOR_TEXT N_("XVMC adaptor number")
97 #define ADAPTOR_LONGTEXT N_( \
98     "If you graphics card provides several adaptors, this option allows you " \
99     "to choose which one will be used (you shouldn't have to change this).")
100
101 #define ALT_FS_TEXT N_("Alternate fullscreen method")
102 #define ALT_FS_LONGTEXT N_( \
103     "There are two ways to make a fullscreen window, unfortunately each one " \
104     "has its drawbacks.\n" \
105     "1) Let the window manager handle your fullscreen window (default), but " \
106     "things like taskbars will likely show on top of the video.\n" \
107     "2) Completely bypass the window manager, but then nothing will be able " \
108     "to show on top of the video.")
109
110 #define DISPLAY_TEXT N_("X11 display name")
111 #define DISPLAY_LONGTEXT N_( \
112     "Specify the X11 hardware display you want to use. By default VLC will " \
113     "use the value of the DISPLAY environment variable.")
114
115 #define CHROMA_TEXT N_("XVimage chroma format")
116 #define CHROMA_LONGTEXT N_( \
117     "Force the XVideo renderer to use a specific chroma format instead of " \
118     "trying to improve performances by using the most efficient one.")
119
120 #define SHM_TEXT N_("Use shared memory")
121 #define SHM_LONGTEXT N_( \
122     "Use shared memory to communicate between VLC and the X server.")
123
124 #define SCREEN_TEXT N_("Screen to be used for fullscreen mode.")
125 #define SCREEN_LONGTEXT N_( \
126     "Choose the screen you want to use in fullscreen mode. For instance " \
127     "set it to 0 for first screen, 1 for the second.")
128
129 #define MODE_TEXT N_("Deinterlace mode")
130 #define MODE_LONGTEXT N_("You can choose the default deinterlace mode")
131
132 #define CROP_TEXT N_("Crop")
133 #define CROP_LONGTEXT N_("You can choose the crop style to apply.")
134
135 vlc_module_begin();
136     set_shortname( "XVMC" );
137     add_string( "xvmc-display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, VLC_TRUE );
138     add_integer( "xvmc-adaptor", -1, NULL, ADAPTOR_TEXT, ADAPTOR_LONGTEXT, VLC_TRUE );
139     add_bool( "xvmc-altfullscreen", 0, NULL, ALT_FS_TEXT, ALT_FS_LONGTEXT, VLC_TRUE );
140     add_string( "xvmc-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT, VLC_TRUE );
141 #ifdef HAVE_SYS_SHM_H
142     add_bool( "xvmc-shm", 1, NULL, SHM_TEXT, SHM_LONGTEXT, VLC_TRUE );
143 #endif
144 #ifdef HAVE_XINERAMA
145     add_integer ( "xvmc-xineramascreen", 0, NULL, SCREEN_TEXT, SCREEN_LONGTEXT, VLC_TRUE );
146 #endif
147     add_string( "xvmc-deinterlace-mode", "bob", NULL, MODE_TEXT, MODE_LONGTEXT, VLC_FALSE );
148     add_string( "xvmc-crop-style", "eq", NULL, CROP_TEXT, CROP_LONGTEXT, VLC_FALSE );
149
150     set_description( _("XVMC extension video output") );
151     set_capability( "video output", 160 );
152     set_callbacks( E_(Activate), E_(Deactivate) );
153 vlc_module_end();
154
155 /* following functions are local */
156
157 static unsigned accel_priority[] = {
158     VLC_XVMC_ACCEL_VLD,
159 };
160
161 #define NUM_ACCEL_PRIORITY (sizeof(accel_priority)/sizeof(accel_priority[0]))
162
163 /*
164  * Additional thread safety, since the plugin may decide to destroy a context
165  * while it's surfaces are still active in the video-out loop.
166  * When / If XvMC libs are reasonably thread-safe, the locks can be made
167  * more efficient by allowing multiple threads in that do not destroy
168  * the context or surfaces that may be active in other threads.
169  */
170
171 static void init_context_lock( context_lock_t *c )
172 {
173     pthread_cond_init(&c->cond,NULL);
174     pthread_mutex_init(&c->mutex,NULL);
175     c->num_readers = 0;
176 }
177
178 void free_context_lock( context_lock_t *c )
179 {
180     pthread_mutex_destroy(&c->mutex);
181     pthread_cond_destroy(&c->cond);
182 }
183
184 void xvmc_context_reader_lock( context_lock_t *c )
185 {
186     pthread_mutex_lock(&c->mutex);
187     c->num_readers++;
188     pthread_mutex_unlock(&c->mutex);
189 }
190
191 void xvmc_context_reader_unlock( context_lock_t *c )
192 {
193     pthread_mutex_lock(&c->mutex);
194     if (c->num_readers > 0) {
195         if (--(c->num_readers) == 0) {
196         pthread_cond_broadcast(&c->cond);
197         }
198     }
199     pthread_mutex_unlock(&c->mutex);
200 }
201
202 void xvmc_context_writer_lock( context_lock_t *c )
203 {
204     pthread_mutex_lock(&c->mutex);
205     while(c->num_readers) {
206         pthread_cond_wait( &c->cond, &c->mutex );
207     }
208 }
209
210 void xvmc_context_writer_unlock( context_lock_t *c )
211 {
212     pthread_mutex_unlock( &c->mutex );
213 }
214
215 void clear_xx44_palette( xx44_palette_t *p )
216 {
217     int i;
218     uint32_t *cluts = p->cluts;
219     int *ids = p->lookup_cache;
220
221     i= p->size;
222     while(i--)
223         *cluts++ = 0;
224     i = 2*OVL_PALETTE_SIZE;
225     while(i--)
226         *ids++ = -1;
227     p->max_used=1;
228 }
229
230 static void init_xx44_palette( xx44_palette_t *p, unsigned num_entries )
231 {
232     p->size = (num_entries > XX44_PALETTE_SIZE) ?
233                     XX44_PALETTE_SIZE : num_entries;
234 }
235
236 static void dispose_xx44_palette(xx44_palette_t *p)
237 {
238     /* Nothing to do */
239 }
240
241 static void colorToPalette( const uint32_t *icolor, unsigned char *palette_p,
242                             unsigned num_xvmc_components, char *xvmc_components )
243 {
244     const clut_t *color = (const clut_t *) icolor;
245     int i;
246
247     for (i=0; i<num_xvmc_components; ++i)
248     {
249         switch(xvmc_components[i])
250         {
251             case 'V': *palette_p = color->cr; break;
252             case 'U': *palette_p = color->cb; break;
253             case 'Y':
254             default:  *palette_p = color->y; break;
255         }
256         *palette_p++;
257     }
258 }
259
260
261 void xx44_to_xvmc_palette( const xx44_palette_t *p,unsigned char *xvmc_palette,
262                            unsigned first_xx44_entry, unsigned num_xx44_entries,
263                            unsigned num_xvmc_components, char *xvmc_components )
264 {
265     int i;
266     const uint32_t *cluts = p->cluts + first_xx44_entry;
267
268     for( i=0; i<num_xx44_entries; ++i )
269     {
270         if( (cluts - p->cluts) < p->size )
271         {
272             colorToPalette( cluts++, xvmc_palette,
273                             num_xvmc_components, xvmc_components );
274             xvmc_palette += num_xvmc_components;
275         }
276     }
277 }
278
279 static int xx44_paletteIndex( xx44_palette_t *p, int color, uint32_t clut )
280 {
281     int i;
282     uint32_t *cluts = p->cluts;
283     int tmp;
284
285     if( (tmp = p->lookup_cache[color]) >= 0 )
286     {
287         if (cluts[tmp] == clut)
288             return tmp;
289     }
290     for (i=0; i<p->max_used; ++i)
291     {
292         if (*cluts++ == clut) {
293             p->lookup_cache[color] = i;
294             return p->lookup_cache[color];
295         }
296     }
297
298     if( p->max_used == (p->size -1) )
299     {
300         //printf("video_out: Warning! Out of xx44 palette colors!\n");
301         return 1;
302     }
303     p->cluts[p->max_used] = clut;
304     p->lookup_cache[color] = p->max_used++;
305     return p->lookup_cache[color];
306 }
307
308 static void memblend_xx44( uint8_t *mem, uint8_t val,
309                            size_t size, uint8_t mask )
310 {
311     uint8_t masked_val = val & mask;
312
313     if (size < 0)
314         return;
315
316     while(size--)
317     {
318         if( (*mem & mask) <= masked_val )
319             *mem = val;
320         mem++;
321     }
322 }
323
324 void blend_xx44( uint8_t *dst_img, subpicture_t *sub_img,
325                  int dst_width, int dst_height, int dst_pitch,
326                  xx44_palette_t *palette, int ia44 )
327 {
328     int src_width;
329     int src_height;
330     int mask;
331     int x_off;
332     int y_off;
333     int x, y;
334     uint8_t norm_pixel,clip_pixel;
335     uint8_t *dst_y;
336     uint8_t *dst;
337     uint8_t alphamask;
338     int clip_right;
339     int i_len, i_color;
340     uint16_t *p_source = NULL;
341     uint16_t i_colprecomp, i_destalpha;
342
343     if (!sub_img)
344         return;
345
346     src_width  = sub_img->i_width;
347     src_height = sub_img->i_height;
348     x_off = sub_img->i_x;
349     y_off = sub_img->i_y;
350     alphamask = (ia44) ? 0x0F : 0xF0;
351     p_source = (uint16_t *)sub_img->p_sys->p_data;
352     i_colprecomp, i_destalpha;
353
354     dst_y = dst_img + dst_pitch*y_off + x_off;
355
356     if( (x_off + sub_img->i_width) <= dst_width )
357         clip_right = sub_img->i_width;
358     else
359         clip_right = dst_width - x_off;
360
361     if ((src_height + y_off) > dst_height)
362         src_height = dst_height - y_off;
363
364     for (y = 0; y < src_height; y++)
365     {
366         mask = !( (y < sub_img->p_sys->i_y_start) ||
367                   (y >= sub_img->p_sys->i_y_end) );
368         dst = dst_y;
369
370         for (x = 0; x < src_width;)
371         {
372             i_color = *p_source & 0x3;
373             i_len = *p_source++ >> 2;
374
375             if( (i_len > 0) && ((x+i_len) <= src_width) )
376             {
377                 /* Get the RLE part, then draw the line */
378                 uint32_t color = (sub_img->p_sys->pi_yuv[i_color][0] << 16) |
379                                  (sub_img->p_sys->pi_yuv[i_color][1] << 0) |
380                                  (sub_img->p_sys->pi_yuv[i_color][2] << 8);
381
382                 norm_pixel = (uint8_t)(
383                             (xx44_paletteIndex( palette,i_color, color ) << 4) |
384                             (sub_img->p_sys->pi_alpha[i_color] & 0x0F) );
385                 clip_pixel = (uint8_t)(
386                             (xx44_paletteIndex( palette,i_color + OVL_PALETTE_SIZE,
387                                                 sub_img->p_sys->pi_yuv[i_color][0] ) << 4) |
388                             (sub_img->p_sys->pi_alpha[i_color] & 0x0F));
389
390                 if( !ia44 )
391                 {
392                     norm_pixel = ((norm_pixel & 0x0F) << 4) | ((norm_pixel & 0xF0) >> 4);
393                     clip_pixel = ((clip_pixel & 0x0F) << 4) | ((clip_pixel & 0xF0) >> 4);
394                 }
395                 if( mask )
396                 {
397                     if( x < sub_img->p_sys->i_x_start )
398                     {
399                         if( (x + i_len) <= sub_img->p_sys->i_x_start )
400                         {
401                             memblend_xx44( dst, norm_pixel, i_len, alphamask );
402                             dst += i_len;
403                         }
404                         else
405                         {
406                             memblend_xx44( dst, norm_pixel,
407                                            sub_img->p_sys->i_x_start - x,
408                                            alphamask );
409                             dst += sub_img->p_sys->i_x_start - x;
410                             i_len -= sub_img->p_sys->i_x_start - x;
411                             if( i_len <= (sub_img->p_sys->i_x_end -
412                                           sub_img->p_sys->i_x_start) )
413                             {
414                                 memblend_xx44( dst, clip_pixel,
415                                                i_len, alphamask);
416                                 dst += i_len;
417                             }
418                             else
419                             {
420                                 memblend_xx44( dst, clip_pixel,
421                                                sub_img->p_sys->i_x_end -
422                                                     sub_img->p_sys->i_x_start,
423                                                alphamask );
424                                 dst += (sub_img->p_sys->i_x_end -
425                                         sub_img->p_sys->i_x_start);
426                                 i_len -= (sub_img->p_sys->i_x_end -
427                                           sub_img->p_sys->i_x_start);
428                                 memblend_xx44( dst, norm_pixel,
429                                                i_len, alphamask );
430                                 dst += i_len;
431                             }
432                         }
433                     }
434                     else if( x < sub_img->p_sys->i_x_end )
435                     {
436                         if( i_len <= (sub_img->p_sys->i_x_end - x) )
437                         {
438                             memblend_xx44( dst, clip_pixel, i_len, alphamask);
439                             dst += i_len;
440                         }
441                         else
442                         {
443                             memblend_xx44( dst, clip_pixel,
444                                            sub_img->p_sys->i_x_end - x,
445                                            alphamask);
446                             dst += (sub_img->p_sys->i_x_end - x);
447                             i_len -= (sub_img->p_sys->i_x_end - x);
448                             memblend_xx44( dst, norm_pixel, i_len, alphamask);
449                             dst += i_len;
450                         }
451                     }
452                     else
453                     {
454                         memblend_xx44( dst, norm_pixel, i_len, alphamask );
455                         dst += i_len;
456                     }
457                 }
458                 else
459                 {
460                     memblend_xx44( dst, norm_pixel, i_len, alphamask );
461                     dst += i_len;
462                 }
463             }
464             else
465             {
466                 return;
467             }
468             x += i_len;
469         }
470         dst_y += dst_pitch;
471     }
472 }
473
474 int xxmc_xvmc_surface_valid( vout_thread_t *p_vout, XvMCSurface *surf )
475 {
476     xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
477     unsigned int index = surf - handler->surfaces;
478     int ret;
479
480     if (index >= XVMC_MAX_SURFACES)
481         return 0;
482     pthread_mutex_lock(&handler->mutex);
483     ret = handler->surfValid[index];
484     pthread_mutex_unlock(&handler->mutex);
485     return ret;
486 }
487
488 static void xxmc_xvmc_dump_subpictures( vout_thread_t *p_vout )
489 {
490     int i;
491     xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
492
493     for( i=0; i < XVMC_MAX_SUBPICTURES; ++i )
494     {
495         msg_Dbg( p_vout, "handler in use %d, valid %d",
496                          handler->subInUse[i],
497                          handler->subValid[i]);
498     }
499 }
500
501 XvMCSubpicture *xxmc_xvmc_alloc_subpicture( vout_thread_t *p_vout,
502                     XvMCContext *context, unsigned short width,
503                     unsigned short height, int xvimage_id )
504 {
505     int i;
506     xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
507     int status;
508
509     pthread_mutex_lock(&handler->mutex);
510     /* xxmc_xvmc_dump_subpictures(p_vout); */
511     for( i=0; i<XVMC_MAX_SUBPICTURES; ++i )
512     {
513         if( handler->subValid[i] && !handler->subInUse[i] )
514         {
515             XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
516             if( XvMCGetSubpictureStatus( p_vout->p_sys->p_display,
517                                          handler->subpictures + i,
518                                          &status ) )
519             {
520                 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
521                 continue;
522             }
523             XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
524             if( status & XVMC_DISPLAYING )
525                 continue;
526             handler->subInUse[i] = 1;
527             /* xxmc_xvmc_dump_subpictures(p_vout); */
528             pthread_mutex_unlock(&handler->mutex);
529             return (handler->subpictures + i);
530         }
531     }
532     for (i=0; i<XVMC_MAX_SUBPICTURES; ++i)
533     {
534         if( !handler->subInUse[i] )
535         {
536             XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
537             if( Success != XvMCCreateSubpicture( p_vout->p_sys->p_display,
538                                                  context,
539                                                  handler->subpictures + i,
540                                                  width, height, xvimage_id ) )
541             {
542                 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
543                 pthread_mutex_unlock( &handler->mutex );
544                 return NULL;
545             }
546             XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
547             msg_Dbg( p_vout, "video_out_xxmc: created subpicture %d\n", i );
548             handler->subInUse[i] = 1;
549             handler->subValid[i] = 1;
550             pthread_mutex_unlock( &handler->mutex );
551             return (handler->subpictures + i);
552         }
553     }
554     pthread_mutex_unlock( &handler->mutex );
555     return NULL;
556 }
557
558 void xxmc_xvmc_free_subpicture( vout_thread_t *p_vout, XvMCSubpicture *sub )
559 {
560     xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
561     unsigned int index = sub - handler->subpictures;
562
563     if( index >= XVMC_MAX_SUBPICTURES )
564         return;
565
566     pthread_mutex_lock( &handler->mutex );
567     handler->subInUse[index] = 0;
568     /* xxmc_xvmc_dump_subpictures(p_vout); */
569     pthread_mutex_unlock( &handler->mutex );
570 }
571
572 static void xxmc_xvmc_surface_handler_construct( vout_thread_t *p_vout )
573 {
574     int i;
575     xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
576  
577     pthread_mutex_init( &handler->mutex, NULL );
578     for( i=0; i<XVMC_MAX_SURFACES; ++i )
579     {
580         handler->surfInUse[i] = 0;
581         handler->surfValid[i] = 0;
582     }
583     for( i=0; i<XVMC_MAX_SUBPICTURES; ++i )
584     {
585         handler->subInUse[i] = 0;
586         handler->subValid[i] = 0;
587     }
588 }
589
590 static void xxmc_xvmc_dump_surfaces( vout_thread_t *p_vout )
591 {
592     int i;
593     xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
594
595     for (i=0; i<XVMC_MAX_SURFACES; ++i)
596     {
597         msg_Dbg(p_vout, "surfaces in use %d, valid %d;",
598                         handler->surfInUse[i],
599                         handler->surfValid[i]);
600     }
601 }
602
603 void xxmc_xvmc_free_surface( vout_thread_t *p_vout, XvMCSurface *surf )
604 {
605     xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
606     unsigned int index = 0;
607
608     index = (surf - handler->surfaces);
609
610     if (index < XVMC_MAX_SURFACES)
611     {
612         pthread_mutex_lock(&handler->mutex);
613         msg_Dbg( p_vout,"free surface %d",index );
614         handler->surfInUse[index]--;
615         xxmc_xvmc_dump_surfaces(p_vout);
616         pthread_mutex_unlock(&handler->mutex);
617     }
618 }
619
620 int checkXvMCCap( vout_thread_t *p_vout )
621 {
622     int i_xvport = 0;
623     int numSurf = 0;
624     int numSub = 0;
625     int i,j;
626     XvMCSurfaceInfo     *surfaceInfo =NULL;
627     XvMCSurfaceInfo     *curInfo = NULL;
628     XvMCContext         c;
629     xvmc_capabilities_t *curCap = NULL;
630     XvImageFormatValues *formatValues = NULL;
631
632     i_xvport = p_vout->p_sys->i_xvport;
633     p_vout->p_sys->xvmc_cap = 0;
634
635     init_context_lock( &p_vout->p_sys->xvmc_lock );
636     xvmc_context_writer_lock( &p_vout->p_sys->xvmc_lock );
637
638     p_vout->p_sys->old_subpic = NULL;
639     p_vout->p_sys->new_subpic = NULL;
640     p_vout->p_sys->contextActive = 0;
641     p_vout->p_sys->subImage = NULL;
642     p_vout->p_sys->hwSubpictures = 0;
643     p_vout->p_sys->xvmc_palette = NULL;
644
645     XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
646
647     if( !XvMCQueryExtension( p_vout->p_sys->p_display,
648                              &p_vout->p_sys->xvmc_eventbase,
649                              &p_vout->p_sys->xvmc_errbase ) )
650     {
651         XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
652         xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
653         return VLC_EGENERIC;
654     }
655     msg_Dbg( p_vout,"XvMC extension found" );
656
657     surfaceInfo = XvMCListSurfaceTypes(p_vout->p_sys->p_display, i_xvport, &numSurf);
658     if( !surfaceInfo )
659     {
660         XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
661         xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
662         return VLC_EGENERIC;
663     }
664
665     p_vout->p_sys->xvmc_cap =
666             (xvmc_capabilities_t *) malloc( numSurf *
667                                             sizeof(xvmc_capabilities_t) );
668     if( !p_vout->p_sys->xvmc_cap )
669     {
670         XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
671         xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
672         return VLC_EGENERIC;
673     }
674
675     p_vout->p_sys->xvmc_num_cap = numSurf;
676     curInfo = surfaceInfo;
677     curCap = p_vout->p_sys->xvmc_cap;
678
679     msg_Dbg( p_vout,"found %d XvMC surface types", numSurf );
680
681     for( i=0; i< numSurf; ++i )
682     {
683         curCap->mpeg_flags = 0;
684         curCap->accel_flags = 0;
685         if( curInfo->chroma_format == XVMC_CHROMA_FORMAT_420 )
686         {
687             curCap->mpeg_flags |= ((curInfo->mc_type & XVMC_MPEG_1) ?
688                                                 VLC_XVMC_MPEG_1 : 0);
689             curCap->mpeg_flags |= ((curInfo->mc_type & XVMC_MPEG_2) ?
690                                                 VLC_XVMC_MPEG_2 : 0);
691             curCap->mpeg_flags |= ((curInfo->mc_type & XVMC_MPEG_4) ?
692                                                 VLC_XVMC_MPEG_4 : 0);
693             curCap->accel_flags |= ((curInfo->mc_type & XVMC_VLD) ?
694                                               VLC_XVMC_ACCEL_VLD : 0);
695             curCap->accel_flags |= ((curInfo->mc_type & XVMC_IDCT) ?
696                                              VLC_XVMC_ACCEL_IDCT : 0);
697             curCap->accel_flags |= ((curInfo->mc_type & (XVMC_VLD | XVMC_IDCT)) ?
698                                             0 : VLC_XVMC_ACCEL_MOCOMP);
699             curCap->max_width = curInfo->max_width;
700             curCap->max_height = curInfo->max_height;
701             curCap->sub_max_width = curInfo->subpicture_max_width;
702             curCap->sub_max_height = curInfo->subpicture_max_height;
703             curCap->flags = curInfo->flags;
704
705             msg_Dbg (p_vout, "surface type %d: Max size: %d %d.",
706                             i, curCap->max_width, curCap->max_height);
707             msg_Dbg (p_vout, "surface subtype %d: Max subpic size: %d %d.",
708                             i, curCap->sub_max_width, curCap->sub_max_height);
709
710             curCap->type_id = curInfo->surface_type_id;
711             formatValues = XvMCListSubpictureTypes( p_vout->p_sys->p_display,
712                                                     i_xvport,
713                                                     curCap->type_id,
714                                                     &numSub );
715             curCap->subPicType.id = 0;
716             if( formatValues )
717             {
718                 msg_Dbg( p_vout, "surface type %d: found %d XvMC subpicture types",
719                                 i, numSub);
720                 for( j = 0; j<numSub; ++j )
721                 {
722                     if( formatValues[j].id == FOURCC_IA44 )
723                     {
724                         curCap->subPicType = formatValues[j];
725                         msg_Dbg( p_vout,
726                                     "surface type %d: detected and using "
727                                     "IA44 subpicture type.", i );
728                         /* Prefer IA44 */
729                         break;
730                     }
731                     else if( formatValues[j].id == FOURCC_AI44 )
732                     {
733                         curCap->subPicType = formatValues[j];
734                         msg_Dbg( p_vout,
735                                  "surface type %d: detected AI44 "
736                                  "subpicture type.", i );
737                     }
738                 }
739             }
740             XFree(formatValues);
741             curInfo++;
742             curCap++;
743         }
744     }
745     XFree(surfaceInfo);
746
747     /*
748     * Try to create a direct rendering context. This will fail if we are not
749     * on the displaying computer or an indirect context is not available.
750     */
751     XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
752     curCap = p_vout->p_sys->xvmc_cap;
753     if( Success == XvMCCreateContext( p_vout->p_sys->p_display, i_xvport,
754                                       curCap->type_id,
755                                       curCap->max_width,
756                                       curCap->max_height,
757                                       XVMC_DIRECT, &c) )
758     {
759             p_vout->p_sys->context_flags = XVMC_DIRECT;
760     }
761     else if( Success == XvMCCreateContext( p_vout->p_sys->p_display, i_xvport,
762                                            curCap->type_id,
763                                            curCap->max_width,
764                                            curCap->max_height,
765                                            0, &c) )
766     {
767         p_vout->p_sys->context_flags = 0;
768     }
769     else
770     {
771         if( p_vout->p_sys->xvmc_cap )
772             free( p_vout->p_sys->xvmc_cap );
773         p_vout->p_sys->xvmc_cap = NULL;
774         msg_Err( p_vout, "use of direct XvMC context on a remote display failed"
775                          " falling back to XV." );
776         xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
777         return VLC_SUCCESS;
778     }
779     XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
780     XvMCDestroyContext( p_vout->p_sys->p_display, &c );
781     xxmc_xvmc_surface_handler_construct(p_vout );
782     /*  p_vout->p_sys->capabilities |= VO_CAP_XXMC; */
783     XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
784     init_xx44_palette( &p_vout->p_sys->palette , 0 );
785     p_vout->p_sys->last_accel_request = 0xFFFFFFFF;
786     xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
787     return VLC_SUCCESS;
788 }
789
790 static int xxmc_setup_subpictures( vout_thread_t *p_vout,
791         unsigned int width, unsigned int height )
792 {
793     xvmc_capabilities_t *curCap = NULL;
794     XvMCSubpicture *sp = NULL;
795
796     if( p_vout->p_sys->contextActive )
797     {
798         curCap = p_vout->p_sys->xvmc_cap + p_vout->p_sys->xvmc_cur_cap;
799
800         if( (width > curCap->sub_max_width) ||
801             (height > curCap->sub_max_height) )
802             return VLC_EGENERIC;
803
804         if( (p_vout->p_sys->xvmc_backend_subpic =
805                 (curCap->flags & XVMC_BACKEND_SUBPICTURE)) )
806             msg_Dbg( p_vout, "using backend subpictures." );
807
808         if (!p_vout->p_sys->subImage)
809         {
810             XLockDisplay( p_vout->p_sys->p_display );
811             msg_Dbg(p_vout, "xxmc_setup_subpictures");
812 #ifdef HAVE_SYS_SHM_H
813             if( p_vout->p_sys->b_shm )
814             {
815                 /* Create image using XShm extension */
816                 p_vout->p_sys->subImage = CreateShmImage( p_vout,
817                                             p_vout->p_sys->p_display,
818                                             p_vout->p_sys->i_xvport,
819                                             curCap->subPicType.id,
820                                             /* VLC2X11_FOURCC( p_vout->output. i_chroma ), */
821                                             &p_vout->p_sys->subShmInfo,
822                                             p_vout->output.i_width,
823                                             p_vout->output.i_height );
824             }
825 #endif /* HAVE_SYS_SHM_H */
826             XUnlockDisplay( p_vout->p_sys->p_display );
827             if( !p_vout->p_sys->subImage )
828             {
829                 msg_Dbg(p_vout, "failed allocating XvImage for supbictures" );
830                 return VLC_EGENERIC;
831             }
832         }
833
834         sp = xxmc_xvmc_alloc_subpicture( p_vout, &p_vout->p_sys->context,
835                                          width, height,
836                                          curCap->subPicType.id );
837         if( !sp == NULL )
838             return VLC_EGENERIC;
839
840         init_xx44_palette( &p_vout->p_sys->palette, sp->num_palette_entries );
841         p_vout->p_sys->xvmc_palette = (char *) malloc( sp->num_palette_entries
842                                                        * sp->entry_bytes );
843         xxmc_xvmc_free_subpicture( p_vout, sp);
844         if( !p_vout->p_sys->xvmc_pallette )
845             return VLC_EGENERIC;
846         p_vout->p_sys->hwSubpictures = 1;
847     }
848     return VLC_SUCCESS;
849 }
850
851 static void xvmc_check_colorkey_properties( vout_thread_t *p_vout )
852 {
853     int num,i;
854     XvAttribute *xvmc_attributes = NULL;
855     Atom ap;
856
857     /*
858     * Determine if the context is of "Overlay" type. If so,
859     * check whether we can autopaint.
860     */
861     p_vout->p_sys->have_xvmc_autopaint = 0;
862     if( p_vout->p_sys->context_flags & XVMC_OVERLAID_SURFACE )
863     {
864         msg_Dbg( p_vout, "check colorkey properties" );
865         XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
866         xvmc_attributes = XvMCQueryAttributes( p_vout->p_sys->p_display,
867                                                &p_vout->p_sys->context,
868                                                &num );
869         if( xvmc_attributes )
870         {
871             for( i = 0; i < num; ++i )
872             {
873                 if( strncmp( "XV_AUTOPAINT_COLORKEY",
874                              xvmc_attributes[i].name,
875                              21) == 0)
876                 {
877                     ap = XInternAtom( p_vout->p_sys->p_display,
878                                       "XV_AUTOPAINT_COLORKEY",
879                                        False );
880                     XvMCSetAttribute( p_vout->p_sys->p_display,
881                                       &p_vout->p_sys->context,
882                                       ap,
883                                       1 ); /* p_vout->p_sys->props[VO_PROP_AUTOPAINT_COLORKEY].value */
884                     p_vout->p_sys->have_xvmc_autopaint = 1;
885                     msg_Dbg( p_vout, "has xvmc autopaint" );
886                 }
887             }
888         }
889         XFree( xvmc_attributes );
890         XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
891         /* p_vout->p_sys->xvmc_xoverlay_type = X11OSD_COLORKEY; */
892     }
893 #if 0
894     else
895     {
896         p_vout->p_sys->xvmc_xoverlay_type = X11OSD_SHAPED;
897     }
898 #endif
899 }
900
901 static void xxmc_xvmc_destroy_surfaces( vout_thread_t *p_vout )
902 {
903     int i;
904     xvmc_surface_handler_t *handler = NULL;
905
906     handler = &p_vout->p_sys->xvmc_surf_handler;
907
908     pthread_mutex_lock( &handler->mutex );
909     for( i = 0; i < XVMC_MAX_SURFACES; ++i )
910     {
911         XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
912         if( handler->surfValid[i] )
913         {
914             XvMCFlushSurface( p_vout->p_sys->p_display , handler->surfaces+i);
915             XvMCSyncSurface( p_vout->p_sys->p_display, handler->surfaces+i );
916             XvMCHideSurface( p_vout->p_sys->p_display, handler->surfaces+i );
917             XvMCDestroySurface( p_vout->p_sys->p_display, handler->surfaces+i );
918         }
919         XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
920         handler->surfValid[i] = 0;
921     }
922     pthread_mutex_unlock( &handler->mutex );
923 }
924
925 static void xxmc_xvmc_destroy_subpictures( vout_thread_t *p_vout )
926 {
927     int i;
928     xvmc_surface_handler_t *handler = NULL;
929
930     handler = &p_vout->p_sys->xvmc_surf_handler;
931
932     pthread_mutex_lock( &handler->mutex );
933     for( i = 0; i < XVMC_MAX_SUBPICTURES; ++i )
934     {
935         XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
936         if( handler->subValid[i] )
937         {
938             XvMCFlushSubpicture( p_vout->p_sys->p_display , handler->subpictures+i);
939             XvMCSyncSubpicture( p_vout->p_sys->p_display, handler->subpictures+i );
940             XvMCDestroySubpicture( p_vout->p_sys->p_display, handler->subpictures+i );
941         }
942         XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
943         handler->subValid[i] = 0;
944     }
945     pthread_mutex_unlock( &handler->mutex );
946 }
947
948 static XvMCSurface *xxmc_xvmc_alloc_surface( vout_thread_t *p_vout,
949         XvMCContext *context )
950 {
951     xvmc_surface_handler_t *handler = NULL;
952     int i;
953
954     handler = &p_vout->p_sys->xvmc_surf_handler;
955
956     pthread_mutex_lock( &handler->mutex );
957     xxmc_xvmc_dump_surfaces( p_vout );
958     for( i = 0; i < XVMC_MAX_SURFACES; ++i )
959     {
960         if( handler->surfValid[i] && !handler->surfInUse[i] )
961         {
962             handler->surfInUse[i] = 1;
963             xxmc_xvmc_dump_surfaces( p_vout );
964             pthread_mutex_unlock( &handler->mutex );
965             return (handler->surfaces + i);
966         }
967     }
968     for( i = 0; i < XVMC_MAX_SURFACES; ++i )
969     {
970         if( !handler->surfInUse[i] )
971         {
972             XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
973             if( Success != XvMCCreateSurface( p_vout->p_sys->p_display
974                                               context,
975                                               handler->surfaces + i) )
976             {
977                 XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
978                 pthread_mutex_unlock( &handler->mutex );
979                 return NULL;
980             }
981             XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
982
983             msg_Dbg( p_vout, "created surface %d", i );
984             handler->surfInUse[i] = 1;
985             handler->surfValid[i] = 1;
986             pthread_mutex_unlock( &handler->mutex );
987             return (handler->surfaces + i);
988         }
989     }
990     pthread_mutex_unlock( &handler->mutex );
991     return NULL;
992 }
993
994 void xxmc_dispose_context( vout_thread_t *p_vout )
995 {
996     if( p_vout->p_sys->contextActive )
997     {
998         if( p_vout->p_sys->xvmc_accel &
999             (VLC_XVMC_ACCEL_MOCOMP | VLC_XVMC_ACCEL_IDCT) )
1000         {
1001             xvmc_macroblocks_t *macroblocks = NULL;
1002
1003             macroblocks = &p_vout->p_sys->macroblocks;
1004             XvMCDestroyMacroBlocks( p_vout->p_sys->p_display,
1005                                     &macroblocks->macro_blocks );
1006             XvMCDestroyBlocks( p_vout->p_sys->p_display,
1007                                &macroblocks->blocks );
1008         }
1009
1010         msg_Dbg( p_vout, "freeing up XvMC surfaces and subpictures" );
1011         if( p_vout->p_sys->xvmc_palette )
1012             free( p_vout->p_sys->xvmc_palette );
1013         dispose_xx44_palette( &p_vout->p_sys->palette );
1014         xxmc_xvmc_destroy_subpictures( p_vout );
1015         xxmc_xvmc_destroy_surfaces( p_vout );
1016
1017         msg_Dbg(p_vout, "freeing up XvMC Context.");
1018         XLockDisplay( p_vout->p_sys->p_display );
1019         if( p_vout->p_sys->subImage )
1020         {
1021             XFree( p_vout->p_sys->subImage );
1022             p_vout->p_sys->subImage = NULL;
1023         }
1024         p_vout->p_sys->subImage = NULL;
1025         XUnlockDisplay( p_vout->p_sys->p_display );
1026         XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
1027         XvMCDestroyContext( p_vout->p_sys->p_display,
1028                             &p_vout->p_sys->context );
1029         XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1030         p_vout->p_sys->contextActive = 0;
1031         p_vout->p_sys->hwSubpictures = 0;
1032         p_vout->p_sys->xvmc_accel = 0;
1033     }
1034 }
1035
1036 static int xxmc_find_context( vout_thread_t *p_vout, vlc_xxmc_t *xxmc,
1037         unsigned int width, unsigned int height )
1038 {
1039     int i, k;
1040     vlc_bool_t found = VLC_FALSE;
1041     xvmc_capabilities_t *curCap = NULL;
1042     unsigned int request_mpeg_flags, request_accel_flags;
1043
1044     request_mpeg_flags = xxmc->mpeg;
1045     for( k = 0; k < NUM_ACCEL_PRIORITY; ++k )
1046     {
1047         request_accel_flags = xxmc->acceleration & accel_priority[k];
1048         if( !request_accel_flags )
1049             continue;
1050
1051         curCap = p_vout->p_sys->xvmc_cap;
1052         for( i =0; i < p_vout->p_sys->xvmc_num_cap; ++i )
1053         {
1054             msg_Dbg( p_vout, "surface type %d, capabilities 0x%8x 0x%8x",
1055                              i,
1056                              curCap->mpeg_flags,
1057                              curCap->accel_flags );
1058             msg_Dbg( p_vout, "fequests: 0x%8x 0x%8x",
1059                              request_mpeg_flags,
1060                              request_accel_flags );
1061             if( ( (curCap->mpeg_flags & request_mpeg_flags) == request_mpeg_flags) &&
1062                   (curCap->accel_flags & request_accel_flags) &&
1063                   (width <= curCap->max_width) &&
1064                   (height <= curCap->max_height) )
1065             {
1066                 found = VLC_TRUE;
1067                 break;
1068             }
1069             curCap++;
1070         }
1071         if( found )
1072         {
1073             p_vout->p_sys->xvmc_cur_cap = i;
1074             break;
1075         }
1076     }
1077     if( found )
1078     {
1079         p_vout->p_sys->xvmc_accel = request_accel_flags;
1080         p_vout->p_sys->unsigned_intra = (curCap->flags & XVMC_INTRA_UNSIGNED);
1081         return 1;
1082     }
1083     p_vout->p_sys->xvmc_accel = 0;
1084     return 0;
1085 }
1086
1087 static int xxmc_create_context( vout_thread_t *p_vout,
1088         unsigned int width, unsigned int height )
1089 {
1090     xvmc_capabilities_t *curCap = NULL;
1091
1092     curCap = p_vout->p_sys->xvmc_cap + p_vout->p_sys->xvmc_cur_cap;
1093
1094     msg_Dbg( p_vout, "creating new XvMC context %d", curCap->type_id );
1095
1096     XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
1097     if( Success == XvMCCreateContext( p_vout->p_sys->p_display,
1098                                       p_vout->p_sys->i_xvport,
1099                                       curCap->type_id,
1100                                       width,
1101                                       height,
1102                                       p_vout->p_sys->context_flags,
1103                                       &p_vout->p_sys->context ) )
1104     {
1105         p_vout->p_sys->xvmc_mpeg = curCap->mpeg_flags;
1106         p_vout->p_sys->xvmc_width = width;
1107         p_vout->p_sys->xvmc_height = height;
1108         p_vout->p_sys->contextActive = 1;
1109     }
1110     XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1111     return p_vout->p_sys->contextActive;
1112 }
1113
1114 static void xvmc_flushsync(picture_t *picture)
1115 {
1116     vout_thread_t *p_vout = picture->p_sys->p_vout;
1117
1118     xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
1119
1120     if( ! xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf)) {
1121         msg_Dbg(p_vout, "xvmc_flushsync 1 : %d", picture->p_sys->xxmc_data.result );
1122         picture->p_sys->xxmc_data.result = 128;
1123         xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1124         return;
1125     }
1126
1127     XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
1128     picture->p_sys->xxmc_data.result =
1129             XvMCFlushSurface( p_vout->p_sys->p_display,
1130                               picture->p_sys->xvmc_surf );
1131     XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1132     xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1133 }
1134
1135 static void xvmc_flush(picture_t *picture)
1136 {
1137     vout_thread_t *p_vout = picture->p_sys->p_vout;
1138
1139     xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
1140
1141     if ( !xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf ) )
1142     {
1143         msg_Dbg(p_vout, "xvmc flush 1 : %d", picture->p_sys->xxmc_data.result );
1144         picture->p_sys->xxmc_data.result = 128;
1145         xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1146         return;
1147     }
1148
1149     XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
1150     picture->p_sys->xxmc_data.result =
1151             XvMCFlushSurface( p_vout->p_sys->p_display,
1152                               picture->p_sys->xvmc_surf );
1153     XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1154     xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1155 }
1156
1157 static int xxmc_frame_updates( vout_thread_t *p_vout, picture_t *picture )
1158 {
1159     vlc_xxmc_t *xxmc = &picture->p_sys->xxmc_data;
1160
1161     /*
1162      * If we have changed context since the surface was updated, xvmc_surf
1163      * is either NULL or invalid. If it is invalid. Set it to NULL.
1164      * Also if there are other users of this surface, deregister our use of
1165      * it and later try to allocate a new, fresh one.
1166      */
1167
1168     if( picture->p_sys->xvmc_surf )
1169     {
1170         if( !xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf ) )
1171         {
1172             xxmc_xvmc_free_surface( p_vout , picture->p_sys->xvmc_surf );
1173             picture->p_sys->xvmc_surf = NULL;
1174         }
1175     }
1176 #if 0
1177     if( picture->p_sys->p_image )
1178     {
1179         memset( picture->p_sys->p_image->data, 0,
1180                 picture->p_sys->p_image->width
1181                     * picture->p_sys->p_image->height );
1182     }
1183 #endif
1184     /*
1185      * If it is NULL create a new surface.
1186      */
1187     if( !picture->p_sys->xvmc_surf )
1188     {
1189         picture->p_sys->xvmc_surf = xxmc_xvmc_alloc_surface( p_vout,
1190                                                     &p_vout->p_sys->context );
1191         if( !picture->p_sys->xvmc_surf )
1192         {
1193             msg_Err( p_vout, "accelerated surface allocation failed.\n"
1194                             " You are probably out of framebuffer memory.\n"
1195                             " Falling back to software decoding." );
1196             p_vout->p_sys->xvmc_accel = 0;
1197             xxmc_dispose_context( p_vout );
1198             return VLC_EGENERIC;
1199         }
1200     }
1201     xxmc->acceleration = p_vout->p_sys->xvmc_accel;
1202
1203     xxmc->proc_xxmc_flush = xvmc_flush;
1204     xxmc->proc_xxmc_flushsync = xvmc_flushsync;
1205     xxmc->xvmc.proc_macro_block = NULL;
1206 #if 0
1207     frame->vo_frame.proc_duplicate_frame_data = xxmc_duplicate_frame_data;
1208 #endif
1209     xxmc->proc_xxmc_begin = xvmc_vld_frame;
1210     xxmc->proc_xxmc_slice = xvmc_vld_slice;
1211     return VLC_SUCCESS;
1212 }
1213
1214 static int xxmc_xvmc_update_context( vout_thread_t *p_vout,
1215     picture_t *picture, uint32_t width, uint32_t height )
1216 {
1217     vlc_xxmc_t *xxmc = &picture->p_sys->xxmc_data;
1218
1219     /*
1220      * Are we at all capable of doing XvMC ?
1221      */
1222     if( p_vout->p_sys->xvmc_cap == 0 )
1223         return VLC_EGENERIC;
1224
1225     msg_Dbg( p_vout, "new format: need to change XvMC context. "
1226                      "width: %d height: %d mpeg: %d acceleration: %d",
1227                      width, height,
1228                      xxmc->mpeg, xxmc->acceleration );
1229
1230     if( picture->p_sys->xvmc_surf )
1231         xxmc_xvmc_free_surface( p_vout , picture->p_sys->xvmc_surf );
1232     picture->p_sys->xvmc_surf = NULL;
1233
1234     xxmc_dispose_context( p_vout );
1235
1236     if( xxmc_find_context( p_vout, xxmc, width, height ) )
1237     {
1238         xxmc_create_context( p_vout, width, height);
1239         xvmc_check_colorkey_properties( p_vout );
1240         xxmc_setup_subpictures(p_vout, width, height);
1241     }
1242
1243     if( !p_vout->p_sys->contextActive )
1244     {
1245         msg_Dbg( p_vout, "using software decoding for this stream" );
1246         p_vout->p_sys->xvmc_accel = 0;
1247     }
1248     else
1249     {
1250         msg_Dbg(p_vout, "using hardware decoding for this stream." );
1251     }
1252
1253     p_vout->p_sys->xvmc_mpeg = xxmc->mpeg;
1254     p_vout->p_sys->xvmc_width = width;
1255     p_vout->p_sys->xvmc_height = height;
1256     return p_vout->p_sys->contextActive;
1257 }
1258
1259
1260 void xxmc_do_update_frame( picture_t *picture, uint32_t width, uint32_t height,
1261         double ratio, int format, int flags)
1262 {
1263     vout_thread_t *p_vout = picture->p_sys->p_vout;
1264     int indextime = 0;
1265     int status = 0;
1266
1267     picture->p_sys->xxmc_data.decoded = 0;
1268     picture->p_sys->nb_display = 0;
1269     picture->b_force = 0;
1270     vlc_xxmc_t *xxmc = &picture->p_sys->xxmc_data;
1271
1272     xvmc_context_writer_lock( &p_vout->p_sys->xvmc_lock);
1273     if( (p_vout->p_sys->last_accel_request != xxmc->acceleration) ||
1274         (p_vout->p_sys->xvmc_mpeg != xxmc->mpeg) ||
1275         (p_vout->p_sys->xvmc_width != width) ||
1276         (p_vout->p_sys->xvmc_height != height))
1277     {
1278         p_vout->p_sys->last_accel_request = xxmc->acceleration;
1279         xxmc_xvmc_update_context( p_vout, picture, width, height );
1280     }
1281
1282     if( p_vout->p_sys->contextActive )
1283         xxmc_frame_updates( p_vout, picture );
1284
1285     if( !p_vout->p_sys->contextActive )
1286     {
1287         xxmc->acceleration = 0;
1288         xxmc->xvmc.macroblocks = 0;
1289     }
1290     else
1291     {
1292         picture->format.i_chroma = format;
1293     }
1294     xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock);
1295
1296     XvMCGetSurfaceStatus( p_vout->p_sys->p_display,
1297                           picture->p_sys->xvmc_surf,
1298                           &status );
1299     /* Wait a little till frame is being displayed */
1300     while( status & XVMC_DISPLAYING )
1301     {
1302         msleep(1);
1303
1304         XvMCGetSurfaceStatus( p_vout->p_sys->p_display,
1305                               picture->p_sys->xvmc_surf,
1306                               &status );
1307
1308         indextime++;
1309         if( indextime > 4 )
1310             break;
1311     }
1312 }
1313
1314 #if 0
1315 /* called xlocked */
1316 static void dispose_ximage( vout_thread_t *p_vout, XShmSegmentInfo *shminfo,
1317                 XvImage *myimage )
1318 {
1319 # ifdef HAVE_SYS_SHM_H
1320     if( p_vout->p_sys->b_shm )
1321     {
1322         XShmDetach( p_vout->p_sys->p_display, shminfo );
1323         XFree( myimage );
1324         shmdt( shminfo->shmaddr );
1325         if( shminfo->shmid >= 0 )
1326         {
1327             shmctl( shminfo->shmid, IPC_RMID, 0 );
1328             shminfo->shmid = -1;
1329         }
1330     }
1331     else
1332 #endif
1333     {
1334         if( myimage->data )
1335             free(myimage->data);
1336         XFree (myimage);
1337     }
1338 }
1339 #endif
1340
1341 void xvmc_vld_frame( picture_t *picture )
1342 {
1343     vout_sys_t *p_sys = picture->p_sys;
1344     vout_thread_t *p_vout = p_sys->p_vout;
1345     vlc_vld_frame_t *vft = &(p_sys->xxmc_data.vld_frame);
1346     picture_t *ff = (picture_t *) vft->forward_reference_picture;
1347     picture_t *bf = (picture_t *) vft->backward_reference_picture;
1348     XvMCMpegControl ctl;
1349     XvMCSurface *fs=0, *bs=0;
1350     XvMCQMatrix qmx;
1351
1352     ctl.BHMV_range = vft->mv_ranges[0][0];
1353     ctl.BVMV_range = vft->mv_ranges[0][1];
1354     ctl.FHMV_range = vft->mv_ranges[1][0];
1355     ctl.FVMV_range = vft->mv_ranges[1][1];
1356     ctl.picture_structure = vft->picture_structure;
1357     ctl.intra_dc_precision = vft->intra_dc_precision;
1358     ctl.picture_coding_type = vft->picture_coding_type;
1359     ctl.mpeg_coding = (vft->mpeg_coding == 0) ? XVMC_MPEG_1 : XVMC_MPEG_2;
1360     ctl.flags = 0;
1361     ctl.flags |= (vft->progressive_sequence) ? XVMC_PROGRESSIVE_SEQUENCE : 0;
1362     ctl.flags |= (vft->scan) ? XVMC_ALTERNATE_SCAN : XVMC_ZIG_ZAG_SCAN;
1363     ctl.flags |= (vft->pred_dct_frame) ?
1364                     XVMC_PRED_DCT_FRAME : XVMC_PRED_DCT_FIELD;
1365     ctl.flags |= (picture->b_top_field_first) ?
1366                     XVMC_TOP_FIELD_FIRST : XVMC_BOTTOM_FIELD_FIRST;
1367     ctl.flags |= (vft->concealment_motion_vectors) ?
1368                     XVMC_CONCEALMENT_MOTION_VECTORS : 0;
1369     ctl.flags |= (vft->q_scale_type) ? XVMC_Q_SCALE_TYPE : 0;
1370     ctl.flags |= (vft->intra_vlc_format) ? XVMC_INTRA_VLC_FORMAT : 0;
1371     ctl.flags |= (vft->second_field) ? XVMC_SECOND_FIELD : 0;
1372
1373     if( ff )
1374         fs = ff->p_sys->xvmc_surf;
1375     if( bf )
1376         bs = bf->p_sys->xvmc_surf;
1377
1378     /*
1379      * Below is for interlaced streams and second_field.
1380      */
1381     if( ctl.picture_coding_type == P_TYPE ) /* XVMC_P_PICTURE) */
1382         bs = picture->p_sys->xvmc_surf;
1383
1384     if( (qmx.load_intra_quantiser_matrix = vft->load_intra_quantizer_matrix) )
1385     {
1386         memcpy( qmx.intra_quantiser_matrix, vft->intra_quantizer_matrix,
1387                 sizeof(qmx.intra_quantiser_matrix) );
1388     }
1389     if( (qmx.load_non_intra_quantiser_matrix =
1390                 vft->load_non_intra_quantizer_matrix) )
1391     {
1392         memcpy( qmx.non_intra_quantiser_matrix, vft->non_intra_quantizer_matrix,
1393                sizeof(qmx.non_intra_quantiser_matrix) );
1394     }
1395     qmx.load_chroma_intra_quantiser_matrix = 0;
1396     qmx.load_chroma_non_intra_quantiser_matrix = 0;
1397     xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
1398
1399     if( ! xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf) )
1400     {
1401         picture->p_sys->xxmc_data.result = 128;
1402         xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1403         return;
1404     }
1405
1406     XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
1407     XvMCLoadQMatrix( p_vout->p_sys->p_display, &p_vout->p_sys->context, &qmx );
1408     do {
1409         picture->p_sys->xxmc_data.result =
1410                 XvMCBeginSurface( p_vout->p_sys->p_display,
1411                                   &p_vout->p_sys->context,
1412                                   picture->p_sys->xvmc_surf,
1413                                   fs, bs, &ctl );
1414     } while( !picture->p_sys->xxmc_data.result );
1415     XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1416     xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1417 }
1418
1419 void xvmc_vld_slice( picture_t *picture )
1420 {
1421     vout_sys_t *p_sys     = picture->p_sys;
1422     vout_thread_t *p_vout = p_sys->p_vout;
1423
1424     xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
1425     if( !xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf ) )
1426     {
1427         picture->p_sys->xxmc_data.result = 128;
1428         xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1429         msg_Err(p_vout, "vld slice error" );
1430         return;
1431     }
1432
1433     XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
1434     picture->p_sys->xxmc_data.result =
1435             XvMCPutSlice2( p_vout->p_sys->p_display,
1436                            &p_vout->p_sys->context,
1437                             picture->p_sys->xxmc_data.slice_data,
1438                             picture->p_sys->xxmc_data.slice_data_size,
1439                             picture->p_sys->xxmc_data.slice_code );
1440
1441     if( picture->p_sys->xxmc_data.result != 0 )
1442         msg_Err( p_vout, "vlc slice error %d",
1443                  picture->p_sys->xxmc_data.result );
1444     /*
1445      * If CPU-saving mode is enabled, sleep after every xxmc->sleep slice. This will free
1446      * up the cpu while the decoder is working on the slice. The value of xxmc->sleep is calculated
1447      * so that the decoder thread sleeps at most 50% of the frame delay,
1448      * assuming a 2.6 kernel clock of 1000 Hz.
1449      */
1450     XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
1451     xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
1452 #if 0
1453     if( p_vout->p_sys->cpu_save_enabled )
1454     {
1455         p_vout->p_sys->cpu_saver += 1.;
1456         if( p_vout->p_sys->cpu_saver >= picture->p_sys->xxmc_data.sleep )
1457         {
1458             usleep(1);
1459             p_vout->p_sys->cpu_saver -= picture->p_sys->xxmc_data.sleep;
1460         }
1461     }
1462 #endif
1463 }