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