~ubuntu-branches/ubuntu/maverick/tvtime/maverick

« back to all changes in this revision

Viewing changes to src/xvoutput.c

  • Committer: Bazaar Package Importer
  • Author(s): Simon Law
  • Date: 2004-01-13 18:00:36 UTC
  • Revision ID: james.westby@ubuntu.com-20040113180036-h996q67t476jymsu
Tags: upstream-0.9.12
ImportĀ upstreamĀ versionĀ 0.9.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Copyright (C) 2002, 2003 Billy Biggs <vektor@dumbterm.net>.
 
3
 *
 
4
 * Helped by XTest code from xine, a free video player,
 
5
 * Copyright (C) 2000-2003 the xine project
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2, or (at your option)
 
10
 * any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software Foundation,
 
19
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
20
 */
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
# include "config.h"
 
24
#endif
 
25
 
 
26
#include "xvoutput.h"
 
27
 
 
28
#ifdef HAVE_XV
 
29
 
 
30
#include <stdio.h>
 
31
#include <stdlib.h>
 
32
#include <string.h>
 
33
#include <sys/ipc.h>
 
34
#include <sys/shm.h>
 
35
#include <X11/X.h>
 
36
#include <X11/Xlib.h>
 
37
#include <X11/extensions/XShm.h>
 
38
#include <X11/extensions/Xv.h>
 
39
#include <X11/extensions/Xvlib.h>
 
40
#include "speedy.h"
 
41
#include "xcommon.h"
 
42
 
 
43
#define FOURCC_YUY2 0x32595559
 
44
 
 
45
static Display *display;
 
46
static Window output_window;
 
47
 
 
48
static XvImage *image;
 
49
static uint8_t *image_data;
 
50
static XShmSegmentInfo shminfo;
 
51
static XvPortID xv_port;
 
52
 
 
53
static int input_width, input_height;
 
54
static int xvoutput_verbose;
 
55
static int xvoutput_error = 0;
 
56
 
 
57
static int HandleXError( Display *display, XErrorEvent *xevent )
 
58
{
 
59
    char str[ 1024 ];
 
60
 
 
61
    if( xevent->error_code == BadAlloc ) {
 
62
        fprintf( stderr, "\n"
 
63
"    Cannot allocate enough off-screen video memory.  This may be fixed by:\n"
 
64
"\n"
 
65
"      1. Closing or restarting large X applications.\n"
 
66
"      2. Lowering the input width of tvtime (--inputwidth parameter).\n"
 
67
"      3. Lowering your colour depth or highest configured resolution.\n"
 
68
"      4. Increasing the amount of video memory in your X config file\n"
 
69
"         (for example, if you are using the i810 XFree86 driver.)\n"
 
70
"\n"
 
71
"    See http://tvtime.net/ for more information.\n\n" );
 
72
 
 
73
    } else {
 
74
        XGetErrorText( display, xevent->error_code, str, 1024 );
 
75
        fprintf( stderr, "xvoutput: Received X error: %s\n", str );
 
76
    }
 
77
    xvoutput_error = 1;
 
78
    return 0;
 
79
}
 
80
 
 
81
static void x11_InstallXErrorHandler( void )
 
82
{
 
83
    XSetErrorHandler( HandleXError );
 
84
    XFlush( display );
 
85
}
 
86
 
 
87
static int xv_port_has_yuy2( XvPortID port )
 
88
{
 
89
    XvImageFormatValues *formatValues;
 
90
    int formats;
 
91
    int i;
 
92
 
 
93
    formatValues = XvListImageFormats( display, port, &formats );
 
94
    for( i = 0; i < formats; i++ ) {
 
95
        if((formatValues[ i ].id == FOURCC_YUY2) && (!(strcmp( formatValues[ i ].guid, "YUY2" )))) {
 
96
            XFree (formatValues);
 
97
            return 1;
 
98
        }
 
99
    }
 
100
    XFree( formatValues );
 
101
    return 0;
 
102
}
 
103
 
 
104
static int xv_check_extension( void )
 
105
{
 
106
    unsigned int version;
 
107
    unsigned int release;
 
108
    unsigned int dummy;
 
109
    unsigned int adaptors;
 
110
    unsigned int i;
 
111
    unsigned long j;
 
112
    int has_yuy2 = 0;
 
113
    XvAdaptorInfo *adaptorInfo;
 
114
 
 
115
    if( ( XvQueryExtension( display, &version, &release,
 
116
                            &dummy, &dummy, &dummy) != Success ) ||
 
117
         ( version < 2 ) || ( ( version == 2 ) && ( release < 2 ) ) ) {
 
118
 
 
119
        fprintf( stderr, "xvoutput: XVIDEO extension not found: X too old? didn't load extmod?\n" );
 
120
        return 0;
 
121
    }
 
122
 
 
123
    XvQueryAdaptors( display, output_window, &adaptors, &adaptorInfo );
 
124
 
 
125
    for( i = 0; i < adaptors; i++ ) {
 
126
        if( adaptorInfo[ i ].type & XvImageMask ) {
 
127
            for( j = 0; j < adaptorInfo[ i ].num_ports; j++ ) {
 
128
                if( xv_port_has_yuy2( adaptorInfo[ i ].base_id + j ) ) {
 
129
                    if( XvGrabPort( display, adaptorInfo[ i ].base_id + j, 0 ) == Success ) {
 
130
                        xv_port = adaptorInfo[ i ].base_id + j;
 
131
                        if( xvoutput_verbose ) {
 
132
                            fprintf( stderr, "xvoutput: Using XVIDEO adaptor %lu: %s.\n",
 
133
                                     adaptorInfo[ i ].base_id + j, adaptorInfo[ i ].name );
 
134
                        }
 
135
                        XvFreeAdaptorInfo( adaptorInfo );
 
136
                        return 1;
 
137
                    }
 
138
                    has_yuy2 = 1;
 
139
                }
 
140
            }
 
141
        }
 
142
    }
 
143
 
 
144
    XvFreeAdaptorInfo( adaptorInfo );
 
145
 
 
146
    if( has_yuy2 ) {
 
147
        fprintf( stderr, "xvoutput: No YUY2 XVIDEO port available.\n" );
 
148
 
 
149
        fprintf( stderr, "\n*** tvtime requires a hardware YUY2 overlay.  One is supported\n"
 
150
                           "*** by your driver, but we could not grab it.  It is likely\n"
 
151
                           "*** being used by another application, either another tvtime\n"
 
152
                           "*** instance or a media player.  Please shut down this other\n"
 
153
                           "*** application and try tvtime again.\n\n" );
 
154
    } else {
 
155
        fprintf( stderr, "xvoutput: No XVIDEO port found which supports YUY2 images.\n" );
 
156
 
 
157
        fprintf( stderr, "\n*** tvtime requires hardware YUY2 overlay support from your video card\n"
 
158
                           "*** driver.  If you are using an older NVIDIA card (TNT2), then\n"
 
159
                           "*** this capability is only available with their binary drivers.\n"
 
160
                           "*** For some ATI cards, this feature may be found in the experimental\n"
 
161
                           "*** GATOS drivers: http://gatos.souceforge.net/\n"
 
162
                           "*** If unsure, please check with your distribution to see if your\n"
 
163
                           "*** X driver supports hardware overlay surfaces.\n\n" );
 
164
    }
 
165
    return 0;
 
166
}
 
167
 
 
168
static void *create_shm( int size )
 
169
{
 
170
    struct shmid_ds shm_info;
 
171
    int error = 1;
 
172
    int major;
 
173
    int minor;
 
174
    Bool pixmaps;
 
175
    int maxid;
 
176
 
 
177
    if( ( XShmQueryVersion( display, &major, &minor, &pixmaps) == 0 ) ||
 
178
         (major < 1) || ((major == 1) && (minor < 1))) {
 
179
        fprintf( stderr, "xvoutput: No xshm extension available.\n" );
 
180
        return 0;
 
181
    }
 
182
 
 
183
    maxid = shmctl( 0, SHM_INFO, &shm_info );
 
184
    if( maxid < 0 ) {
 
185
        fprintf( stderr, "\n"
 
186
          "    Your kernel has been compiled without support for shared\n"
 
187
          "    memory.  Please fix this in your kernel before running\n"
 
188
          "    tvtime.\n\n" );
 
189
        return 0;
 
190
    }
 
191
 
 
192
    shminfo.shmid = shmget( IPC_PRIVATE, size, IPC_CREAT | 0777 );
 
193
    if( shminfo.shmid != -1 ) {
 
194
        shminfo.shmaddr = (char *) shmat( shminfo.shmid, 0, 0 );
 
195
        if( shminfo.shmaddr != (char *)-1 ) {
 
196
 
 
197
            /**
 
198
             * XShmAttach fails on remote displays, so we have to catch
 
199
             * this event.
 
200
             */
 
201
 
 
202
            XSync( display, False );
 
203
            x11_InstallXErrorHandler();
 
204
 
 
205
            shminfo.readOnly = True;
 
206
            if( XShmAttach( display, &shminfo ) ) {
 
207
                error = 0;
 
208
            } else {
 
209
                fprintf( stderr, "xvoutput: tvtime cannot run on a remote X server.\n" );
 
210
            }
 
211
 
 
212
            XSync( display, False );
 
213
 
 
214
            /**
 
215
             * We immediately delete the shared memory segment to ensure
 
216
             * that we clean up after crashes.
 
217
             */
 
218
            shmctl( shminfo.shmid, IPC_RMID, 0 );
 
219
        }
 
220
    } else {
 
221
        fprintf( stderr, "xvoutput: Out of memory.\n" );
 
222
    }
 
223
 
 
224
    if( error ) {
 
225
        return 0;
 
226
    } else {
 
227
        return shminfo.shmaddr;
 
228
    }
 
229
}
 
230
 
 
231
static int xv_alloc_frame( void )
 
232
{
 
233
    int size;
 
234
    uint8_t *alloc;
 
235
 
 
236
    size = input_width * input_height * 2;
 
237
    alloc = create_shm( size );
 
238
    if( alloc ) {
 
239
        /* Initialize the input image to black. */
 
240
        blit_colour_packed422_scanline( alloc, input_width * input_height,
 
241
                                        16, 128, 128 );
 
242
        image = XvShmCreateImage( display, xv_port, FOURCC_YUY2, (char *) alloc,
 
243
                                  input_width, input_height, &shminfo );
 
244
        image_data = alloc;
 
245
        return 1;
 
246
    }
 
247
 
 
248
    return 0;
 
249
}
 
250
 
 
251
static int get_colourkey( void )
 
252
{
 
253
    Atom atom;
 
254
    XvAttribute *attr;
 
255
    int value;
 
256
    int nattr;
 
257
 
 
258
    attr = XvQueryPortAttributes( display, xv_port, &nattr );
 
259
    if( attr ) {
 
260
        if( nattr ) {
 
261
            int k;
 
262
 
 
263
            for( k = 0; k < nattr; k++ ) {
 
264
                if( (attr[ k ].flags & XvSettable) && (attr[ k ].flags & XvGettable)) {
 
265
                    if( !strcmp( attr[ k ].name, "XV_COLORKEY" ) ) {
 
266
                        atom = XInternAtom( display, "XV_COLORKEY", False );
 
267
                        if( atom != None ) {
 
268
                            XvGetPortAttribute( display, xv_port, atom, &value );
 
269
                            XvSetPortAttribute( display, xv_port, atom, value );
 
270
                            XvGetPortAttribute( display, xv_port, atom, &value );
 
271
                            XFree( attr );
 
272
                            return value;
 
273
                        }
 
274
                    }
 
275
                }
 
276
            }
 
277
        }
 
278
        XFree( attr );
 
279
    }
 
280
    return 0;
 
281
}
 
282
 
 
283
static int xv_init( int outputheight, int aspect, int verbose )
 
284
{
 
285
    xvoutput_verbose = verbose;
 
286
 
 
287
    if( !xcommon_open_display( aspect, outputheight, verbose ) ) {
 
288
        return 0;
 
289
    }
 
290
    display = xcommon_get_display();
 
291
    output_window = xcommon_get_output_window();
 
292
 
 
293
    if( !xv_check_extension() ) return 0;
 
294
    xcommon_set_colourkey( get_colourkey() );
 
295
    return 1;
 
296
}
 
297
 
 
298
static int xv_show_frame( int x, int y, int width, int height )
 
299
{
 
300
    area_t video_area = xcommon_get_video_area();
 
301
    area_t scale_area;
 
302
 
 
303
    scale_area.x = x;
 
304
    scale_area.y = y;
 
305
    scale_area.width = width;
 
306
    scale_area.height = height;
 
307
 
 
308
    xcommon_set_video_scale( scale_area );
 
309
 
 
310
    xcommon_ping_screensaver();
 
311
    XvShmPutImage( display, xv_port, output_window, xcommon_get_gc(), image,
 
312
                   x, y, width, height,
 
313
                   video_area.x, video_area.y,
 
314
                   video_area.width, video_area.height, False );
 
315
    xcommon_frame_drawn();
 
316
    XSync( display, False );
 
317
    if( xvoutput_error ) return 0;
 
318
    return 1;
 
319
}
 
320
 
 
321
static int xv_set_input_size( int inputwidth, int inputheight )
 
322
{
 
323
    input_width = inputwidth;
 
324
    input_height = inputheight;
 
325
 
 
326
    if( !xv_alloc_frame() ) {
 
327
        return 0;
 
328
    }
 
329
 
 
330
    xv_show_frame( 0, 0, input_width, input_height );
 
331
    xcommon_clear_screen();
 
332
    return 1;
 
333
}
 
334
 
 
335
static void xv_quit( void )
 
336
{
 
337
    XShmDetach( display, &shminfo );
 
338
    shmdt( shminfo.shmaddr );
 
339
    xcommon_close_display();
 
340
}
 
341
 
 
342
static int xv_get_stride( void )
 
343
{
 
344
    return image->pitches[ 0 ];
 
345
}
 
346
 
 
347
static int xv_is_interlaced( void )
 
348
{
 
349
    return 0;
 
350
}
 
351
 
 
352
static void xv_wait_for_sync( int field )
 
353
{
 
354
}
 
355
 
 
356
static void xv_lock_output( void )
 
357
{
 
358
}
 
359
 
 
360
static void xv_unlock_output( void )
 
361
{
 
362
}
 
363
 
 
364
static uint8_t *xv_get_output( void )
 
365
{
 
366
    return image_data;
 
367
}
 
368
 
 
369
static int xv_can_read_from_buffer( void )
 
370
{
 
371
    return 1;
 
372
}
 
373
 
 
374
static int xv_is_overscan_supported( void )
 
375
{
 
376
    return 1;
 
377
}
 
378
 
 
379
static output_api_t xvoutput =
 
380
{
 
381
    xv_init,
 
382
 
 
383
    xv_set_input_size,
 
384
 
 
385
    xv_lock_output,
 
386
    xv_get_output,
 
387
    xv_get_stride,
 
388
    xv_can_read_from_buffer,
 
389
    xv_unlock_output,
 
390
 
 
391
    xcommon_is_exposed,
 
392
    xcommon_get_visible_width,
 
393
    xcommon_get_visible_height,
 
394
    xcommon_is_fullscreen,
 
395
    xcommon_is_alwaysontop,
 
396
 
 
397
    xcommon_is_fullscreen_supported,
 
398
    xcommon_is_alwaysontop_supported,
 
399
    xv_is_overscan_supported,
 
400
 
 
401
    xv_is_interlaced,
 
402
    xv_wait_for_sync,
 
403
    xv_show_frame,
 
404
 
 
405
    xcommon_toggle_aspect,
 
406
    xcommon_toggle_alwaysontop,
 
407
    xcommon_toggle_fullscreen,
 
408
    xcommon_resize_window_fullscreen,
 
409
    xcommon_set_window_caption,
 
410
 
 
411
    xcommon_set_window_position,
 
412
    xcommon_set_window_height,
 
413
    xcommon_set_fullscreen_position,
 
414
    xcommon_set_matte,
 
415
 
 
416
    xcommon_poll_events,
 
417
    xv_quit
 
418
};
 
419
 
 
420
output_api_t *get_xv_output( void )
 
421
{
 
422
    return &xvoutput;
 
423
}
 
424
 
 
425
#else
 
426
 
 
427
output_api_t *get_xv_output( void )
 
428
{
 
429
    return 0;
 
430
}
 
431
 
 
432
#endif
 
433