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