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