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