root/pytyxi/xine.py

Revision 1483, 24.3 kB (checked in by Alexandre Rossi <alexandre.rossi@…>, 2 months ago)

[pytyxi] fix xine UI message retrieval from xinelib

Line 
1# Deejayd, a media player daemon
2# Copyright (C) 2007-2009 Mickael Royer <mickael.royer@gmail.com>
3#                         Alexandre Rossi <alexandre.rossi@gmail.com>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program; if not, write to the Free Software Foundation, Inc.,
17# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18#
19# This work is based on the perl Video::Xine API.
20# http://search.cpan.org/~stephen/Video-Xine/
21
22
23import ctypes, os
24import _xinelib as xinelib
25import x11
26
27
28class XineError(Exception): pass
29
30
31class Osd(object):
32
33    XINE_TEXT_PALETTE_SIZE = 11
34
35    XINE_OSD_TEXT1  = (0 * XINE_TEXT_PALETTE_SIZE)
36    XINE_OSD_TEXT2  = (1 * XINE_TEXT_PALETTE_SIZE)
37    XINE_OSD_TEXT3  = (2 * XINE_TEXT_PALETTE_SIZE)
38    XINE_OSD_TEXT4  = (3 * XINE_TEXT_PALETTE_SIZE)
39    XINE_OSD_TEXT5  = (4 * XINE_TEXT_PALETTE_SIZE)
40    XINE_OSD_TEXT6  = (5 * XINE_TEXT_PALETTE_SIZE)
41    XINE_OSD_TEXT7  = (6 * XINE_TEXT_PALETTE_SIZE)
42    XINE_OSD_TEXT8  = (7 * XINE_TEXT_PALETTE_SIZE)
43    XINE_OSD_TEXT9  = (8 * XINE_TEXT_PALETTE_SIZE)
44    XINE_OSD_TEXT10 = (9 * XINE_TEXT_PALETTE_SIZE)
45
46    # white text, black border, transparent background
47    XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT    = 0
48    # white text, noborder, transparent background
49    XINE_TEXTPALETTE_WHITE_NONE_TRANSPARENT     = 1
50    # white text, no border, translucid background
51    XINE_TEXTPALETTE_WHITE_NONE_TRANSLUCID      = 2
52    # yellow text, black border, transparent background
53    XINE_TEXTPALETTE_YELLOW_BLACK_TRANSPARENT   = 3
54
55    XINE_OSD_CAP_FREETYPE2 = 0x0001
56    XINE_OSD_CAP_UNSCALED  = 0x0002
57
58    def __init__(self, stream, width, height):
59        self.__osd_p = xinelib.xine_osd_new(stream.stream_p(),
60                                            0, 0, width, height)
61        self.color_base = Osd.XINE_OSD_TEXT1
62        self.__last_text = None
63
64    def set_font(self, font_name, font_size):
65        xinelib.xine_osd_set_font(self.__osd_p, font_name, font_size)
66
67    def set_text_palette(self, palette_number, color_base):
68        self.color_base = color_base
69        xinelib.xine_osd_set_text_palette(self.__osd_p,
70                                          palette_number,
71                                          color_base)
72
73    def is_unscaled(self):
74        unscaled = xinelib.xine_osd_get_capabilities(self.__osd_p)\
75                   & Osd.XINE_OSD_CAP_UNSCALED
76        return unscaled and True or False
77
78    def clear(self):
79        xinelib.xine_osd_clear(self.__osd_p)
80
81    def draw_text(self, posx, posy, text):
82        xinelib.xine_osd_draw_text(self.__osd_p,
83                                   0, 0, text, self.color_base)
84        xinelib.xine_osd_set_position(self.__osd_p, posx, posy)
85        self.__last_text = text
86
87    def show(self):
88        if self.is_unscaled:
89            xinelib.xine_osd_show_unscaled(self.__osd_p, 0)
90        else:
91            xinelib.xine_osd_show(self.__osd_p, 0)
92
93    def hide(self, text):
94        if text == self.__last_text:
95            xinelib.xine_osd_hide(self.__osd_p, 0)
96
97    def close(self):
98        self.clear()
99        xinelib.xine_osd_free(self.__osd_p)
100        self.__osd_p = None
101
102
103class Event(object):
104
105    XINE_EVENT_UI_PLAYBACK_FINISHED = 1
106    XINE_EVENT_UI_CHANNELS_CHANGED  = 2
107    XINE_EVENT_UI_SET_TITLE         = 3
108    XINE_EVENT_UI_MESSAGE           = 4
109    XINE_EVENT_FRAME_FORMAT_CHANGE  = 5
110    XINE_EVENT_AUDIO_LEVEL          = 6
111    XINE_EVENT_QUIT                 = 7
112    XINE_EVENT_PROGRESS             = 8
113
114    def __init__(self, type, contents):
115        self.type = type
116        if self.type == Event.XINE_EVENT_UI_MESSAGE:
117            self.data = ctypes.cast(contents.data,
118                             ctypes.POINTER(xinelib.xine_ui_message_data_t))
119        else:
120            self.data = None
121
122    def message(self):
123        if not self.data: return None
124        msg = self.data.contents
125        if msg.type != XinePlayer.XINE_MSG_NO_ERROR:
126            if msg.explanation:
127                message_txt = ctypes.string_at(ctypes.addressof(msg)\
128                              + msg.explanation)
129                message_parameters = []
130                param_address = ctypes.addressof(msg) + msg.parameters
131                for param_index in range(0, msg.num_parameters):
132                    message_par = ctypes.string_at(param_address)
133                    param_address += len(message_par) + 2 # Skip '\0'
134                    message_parameters.append(message_par)
135                message_params = ' '.join(message_parameters)
136                message = "%s %s" % (message_txt, message_params)
137            else:
138                raise XineError(msg.type)
139        else:
140            message = None
141        return message
142
143
144class EventQueue(object):
145
146    def __init__(self, stream):
147        self.__callbacks = []
148        self.__event_queue_p = xinelib.xine_event_new_queue(stream.stream_p())
149
150    def add_callback(self, callback, user_data=None):
151        cb = xinelib.xine_event_listener_cb_t(self.__get_cb(callback))
152        self.__callbacks.append(cb)
153        xinelib.xine_event_create_listener_thread(self.__event_queue_p,
154                                                  cb, user_data)
155
156    def __get_cb(self, callback):
157        def c_cb(user_data, event):
158            callback(user_data, Event(event.contents.type, event.contents))
159        return c_cb
160
161    def close(self):
162        xinelib.xine_event_dispose_queue(self.__event_queue_p)
163        self.__callbacks = []
164
165
166class AudioDriver(object):
167
168    def __init__(self, xine, id=None, data=None):
169        self.__xine_p = xine.xine_p()
170        self.__driver_p = xinelib.xine_open_audio_driver(self.__xine_p,
171                                                         id, data)
172        if not self.__driver_p:
173            raise XineError('Could not open audio driver')
174
175    def driver_p(self):
176        return self.__driver_p
177
178    def destroy(self):
179        xinelib.xine_close_audio_driver(self.__xine_p, self.__driver_p)
180        self.__driver_p = None
181
182
183class VideoDriver(object):
184
185    XINE_VISUAL_TYPE_NONE    = 0
186    XINE_VISUAL_TYPE_X11     = 1
187    XINE_VISUAL_TYPE_X11_2   = 10
188    XINE_VISUAL_TYPE_AA      = 2
189    XINE_VISUAL_TYPE_FB      = 3
190    XINE_VISUAL_TYPE_GTK     = 4
191    XINE_VISUAL_TYPE_DFB     = 5
192    XINE_VISUAL_TYPE_PM      = 6
193    XINE_VISUAL_TYPE_DIRECTX = 7
194    XINE_VISUAL_TYPE_CACA    = 8
195    XINE_VISUAL_TYPE_MACOSX  = 9
196    XINE_VISUAL_TYPE_XCB     = 11
197
198    def __init__(self, xine, id=None, display_id=':0.0', fullscreen=False):
199        self.__xine_p = xine.xine_p()
200
201        try:
202            visual = self.__make_x11_visual(display_id, fullscreen)
203        except x11.X11Error:
204            raise XineError('Could not initialize Xine on %s', display_id)
205
206        self.__driver_p = xinelib.xine_open_video_driver(self.__xine_p,
207                           id,
208                           VideoDriver.XINE_VISUAL_TYPE_X11,
209                           ctypes.cast(ctypes.byref(visual), ctypes.c_void_p))
210
211        if not self.__driver_p:
212            raise XineError('Could not open video driver')
213
214    def driver_p(self):
215        return self.__driver_p
216
217    def __make_x11_visual(self, display_id, fullscreen=False):
218        self.display = x11.X11Display(display_id)
219        if fullscreen:
220            self.window = self.display.do_create_window(fullscreen=True)
221        else:
222            self.window = self.display.do_create_window(320, 200)
223
224        # Those callbacks are required to be kept in this tuple in order to
225        # be safe from the garbage collector.
226        self.__x11_callbacks = ( xinelib.xine_dest_size_cb(self.__dest_size_cb),
227                           xinelib.xine_frame_output_cb(self.__frame_output_cb),
228                               )
229
230        vis = xinelib.x11_visual_t()
231        vis.display = self.display.display_p()
232        vis.screen = self.display.get_default_screen_number()
233        vis.d = self.window.window_p()
234        vis.frame_output_cb = ctypes.cast(self.__x11_callbacks[1],
235                                          ctypes.c_void_p)
236        vis.dest_size_cb = ctypes.cast(self.__x11_callbacks[0], ctypes.c_void_p)
237        return vis
238
239    def __frame_output_cb(self, user_data,
240                                video_width, video_height, video_pixel_aspect,
241                                dest_x, dest_y,
242                                dest_width, dest_height, dest_pixel_aspect,
243                                win_x, win_y):
244        dest_x[0] = 0
245        dest_y[0] = 0
246        win_x[0] = self.window.video_area_info['win_x']
247        win_y[0] = self.window.video_area_info['win_y']
248        self.__dest_size_cb(user_data,
249                            video_width, video_height, video_pixel_aspect,
250                            dest_width, dest_height, dest_pixel_aspect)
251
252    def __dest_size_cb(self, user_data,
253                             video_width, video_height, video_pixel_aspect,
254                             dest_width, dest_height, dest_pixel_aspect):
255        dest_width[0] = self.window.video_area_info['width']
256        dest_height[0] = self.window.video_area_info['height']
257        dest_pixel_aspect[0] = self.window.video_area_info['aspect']
258
259    XINE_GUI_SEND_DRAWABLE_CHANGED       = 2
260    XINE_GUI_SEND_EXPOSE_EVENT           = 3
261    XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO = 4
262    XINE_GUI_SEND_VIDEOWIN_VISIBLE       = 5
263    XINE_GUI_SEND_SELECT_VISUAL          = 8
264    XINE_GUI_SEND_WILL_DESTROY_DRAWABLE  = 9
265
266    def send_gui_data(self, type, data=None):
267        xinelib.xine_port_send_gui_data(self.__driver_p, ctypes.c_int(type),
268                                        ctypes.cast(data, ctypes.c_void_p))
269
270    def destroy(self):
271        xinelib.xine_close_video_driver(self.__xine_p, self.__driver_p)
272        self.__x11_callbacks = None
273        self.__driver = None
274
275        self.window.close()
276        self.window = None
277        self.display.destroy()
278        self.display = None
279
280
281class Stream(object):
282
283    XINE_SPEED_PAUSE                 =  0
284    XINE_SPEED_SLOW_4                =  1
285    XINE_SPEED_SLOW_2                =  2
286    XINE_SPEED_NORMAL                =  4
287    XINE_SPEED_FAST_2                =  8
288    XINE_SPEED_FAST_4                = 16
289
290    def __init__(self, xine, audio_port=None, video_port=None):
291        self.__xine = xine
292        self.__event_queue = None
293        self.__software_mixer = False
294        self.__audio_port = audio_port or AudioDriver(xine)
295        self.__video_port = video_port
296        if self.__video_port:
297            video_driver_p = self.__video_port.driver_p()
298        else:
299            video_driver_p = None
300        self.__stream_p = xinelib.xine_stream_new(self.__xine.xine_p(),
301                                                  self.__audio_port.driver_p(),
302                                                  video_driver_p)
303
304        if self.__xine.has_gapless():
305            self.set_param(Stream.XINE_PARAM_EARLY_FINISHED_EVENT, 1)
306
307        if self.__video_port:
308            self.__video_port.send_gui_data(\
309                              VideoDriver.XINE_GUI_SEND_DRAWABLE_CHANGED,
310                              self.__video_port.window.window_p())
311            self.__video_port.send_gui_data(\
312                              VideoDriver.XINE_GUI_SEND_VIDEOWIN_VISIBLE,
313                              1)
314        else:
315            self.set_param(Stream.XINE_PARAM_IGNORE_VIDEO, 1)
316            self.set_param(Stream.XINE_PARAM_IGNORE_SPU, 1)
317
318        self.__osd = None
319
320    def has_video(self):
321        if self.__video_port:
322            return True
323        else:
324            return False
325
326    def stream_p(self):
327        return self.__stream_p
328
329    def add_event_callback(self, callback):
330        if not self.__event_queue:
331            self.__event_queue = EventQueue(self)
332        self.__event_queue.add_callback(callback)
333
334    def open(self, mrl):
335        if not xinelib.xine_open(self.__stream_p, mrl):
336            raise XineError('Could not open %s' % mrl)
337
338    def play(self, start_pos=0, start_time=0):
339        if not xinelib.xine_play(self.__stream_p, ctypes.c_int(start_pos),
340                                                  ctypes.c_int(start_time)):
341            raise XineError('Could not play stream')
342        else:
343            self.set_dpms(False)
344
345    def stop(self):
346        self.set_dpms(False)
347        xinelib.xine_stop(self.__stream_p)
348
349    def get_pos_length(self):
350        _pos_stream = ctypes.c_int()
351        _pos_time = ctypes.c_int()
352        _length_time = ctypes.c_int()
353        result = xinelib.xine_get_pos_length(self.__stream_p,
354                                             ctypes.byref(_pos_stream),
355                                             ctypes.byref(_pos_time),
356                                             ctypes.byref(_length_time))
357        if result:
358            return _pos_stream.value, _pos_time.value, _length_time.value
359        else:
360            return 0, 0, 0
361
362    def get_pos(self):
363        # Workaround for problems when you seek too quickly
364        i = 0
365        while i < 4:
366            pos_s, pos_t, length = self.get_pos_length()
367            if int(pos_t) > 0:  break
368            xinelib.xine_usec_sleep(100000)
369            i += 1
370        return int(pos_t / 1000)
371
372    def get_length(self):
373        pos_s, pos_t, length = self.get_pos_length()
374        return length / 1000
375
376    XINE_STATUS_IDLE = 0
377    XINE_STATUS_STOP = 1
378    XINE_STATUS_PLAY = 2
379    XINE_STATUS_QUIT = 3
380
381    def get_status(self):
382        return xinelib.xine_get_status(self.__stream_p)
383
384    def set_fullscreen(self, fullscreen):
385        # FIXME : This does not work yet.
386        raise NotImplementedError
387        if not self.__video_port:
388            raise XineError('Stream is audio only')
389        self.__video_port.window.set_fullscreen(fullscreen)
390        self.__video_port.send_gui_data(\
391                              VideoDriver.XINE_GUI_SEND_DRAWABLE_CHANGED,
392                              self.__video_port.window.window_p())
393
394    XINE_PARAM_SPEED                 =  1 # see below
395    XINE_PARAM_AV_OFFSET             =  2 # unit: 1/90000 sec
396    XINE_PARAM_AUDIO_CHANNEL_LOGICAL =  3 # 1 => auto, -2 => off
397    XINE_PARAM_SPU_CHANNEL           =  4
398    XINE_PARAM_VIDEO_CHANNEL         =  5
399    XINE_PARAM_AUDIO_VOLUME          =  6 # 0..100
400    XINE_PARAM_AUDIO_MUTE            =  7 # 1=>mute, 0=>unmute
401    XINE_PARAM_AUDIO_COMPR_LEVEL     =  8 # <100=>off, % compress otherw
402    XINE_PARAM_AUDIO_AMP_LEVEL       =  9 # 0..200, 100=>100% (default)
403    XINE_PARAM_AUDIO_REPORT_LEVEL    = 10 # 1=>send events, 0=> don't
404    XINE_PARAM_VERBOSITY             = 11 # control console output
405    XINE_PARAM_SPU_OFFSET            = 12 # unit: 1/90000 sec
406    XINE_PARAM_IGNORE_VIDEO          = 13 # disable video decoding
407    XINE_PARAM_IGNORE_AUDIO          = 14 # disable audio decoding
408    XINE_PARAM_IGNORE_SPU            = 15 # disable spu decoding
409    XINE_PARAM_BROADCASTER_PORT      = 16 # 0: disable, x: server port
410    XINE_PARAM_METRONOM_PREBUFFER    = 17 # unit: 1/90000 sec
411    XINE_PARAM_EQ_30HZ               = 18 # equalizer gains -100..100
412    XINE_PARAM_EQ_60HZ               = 19 # equalizer gains -100..100
413    XINE_PARAM_EQ_125HZ              = 20 # equalizer gains -100..100
414    XINE_PARAM_EQ_250HZ              = 21 # equalizer gains -100..100
415    XINE_PARAM_EQ_500HZ              = 22 # equalizer gains -100..100
416    XINE_PARAM_EQ_1000HZ             = 23 # equalizer gains -100..100
417    XINE_PARAM_EQ_2000HZ             = 24 # equalizer gains -100..100
418    XINE_PARAM_EQ_4000HZ             = 25 # equalizer gains -100..100
419    XINE_PARAM_EQ_8000HZ             = 26 # equalizer gains -100..100
420    XINE_PARAM_EQ_16000HZ            = 27 # equalizer gains -100..100
421    XINE_PARAM_AUDIO_CLOSE_DEVICE    = 28 # force closing audio device
422    XINE_PARAM_AUDIO_AMP_MUTE        = 29 # 1=>mute, 0=>unmute
423    XINE_PARAM_FINE_SPEED            = 30 # 1.000.000 => normal speed
424    XINE_PARAM_EARLY_FINISHED_EVENT  = 31 # send event when demux finish
425    XINE_PARAM_GAPLESS_SWITCH        = 32 # next stream only gapless swi
426    XINE_PARAM_DELAY_FINISHED_EVENT  = 33 # 1/10sec,0=>disable,-1=>f
427
428    XINE_PARAM_VO_DEINTERLACE        = 0x01000000 # bool
429    XINE_PARAM_VO_ASPECT_RATIO       = 0x01000001 # see below
430    XINE_PARAM_VO_HUE                = 0x01000002 # 0..65535
431    XINE_PARAM_VO_SATURATION         = 0x01000003 # 0..65535
432    XINE_PARAM_VO_CONTRAST           = 0x01000004 # 0..65535
433    XINE_PARAM_VO_BRIGHTNESS         = 0x01000005 # 0..65535
434    XINE_PARAM_VO_ZOOM_X             = 0x01000008 # percent
435    XINE_PARAM_VO_ZOOM_Y             = 0x0100000d # percent
436    XINE_PARAM_VO_PAN_SCAN           = 0x01000009 # bool
437    XINE_PARAM_VO_TVMODE             = 0x0100000a # ???
438    XINE_PARAM_VO_WINDOW_WIDTH       = 0x0100000f # readonly
439    XINE_PARAM_VO_WINDOW_HEIGHT      = 0x01000010 # readonly
440    XINE_PARAM_VO_CROP_LEFT          = 0x01000020 # crop frame pixels
441    XINE_PARAM_VO_CROP_RIGHT         = 0x01000021 # crop frame pixels
442    XINE_PARAM_VO_CROP_TOP           = 0x01000022 # crop frame pixels
443    XINE_PARAM_VO_CROP_BOTTOM        = 0x01000023 # crop frame pixels
444
445    XINE_VO_ZOOM_STEP                = 100
446    XINE_VO_ZOOM_MAX                 = 400
447    XINE_VO_ZOOM_MIN                 = -85
448
449    XINE_VO_ASPECT_AUTO              = 0
450    XINE_VO_ASPECT_SQUARE            = 1 # 1:1
451    XINE_VO_ASPECT_4_3               = 2 # 4:3
452    XINE_VO_ASPECT_ANAMORPHIC        = 3 # 16:9
453    XINE_VO_ASPECT_DVB               = 4 # 2.11:1
454    XINE_VO_ASPECT_NUM_RATIOS        = 5
455
456    def set_param(self, param, value):
457        xinelib.xine_set_param(self.__stream_p, param, value)
458
459    def get_param(self, param):
460        return xinelib.xine_get_param(self.__stream_p, param)
461
462    def set_software_mixer(self, software_mixer):
463        self.__software_mixer = software_mixer
464
465    def set_volume(self, volume):
466        param = Stream.XINE_PARAM_AUDIO_VOLUME
467        if self.__software_mixer:
468            param = Stream.XINE_PARAM_AUDIO_AMP_LEVEL
469        self.set_param(param, volume)
470
471    XINE_META_INFO_TITLE             = 0
472    XINE_META_INFO_COMMENT           = 1
473    XINE_META_INFO_ARTIST            = 2
474    XINE_META_INFO_GENRE             = 3
475    XINE_META_INFO_ALBUM             = 4
476    XINE_META_INFO_YEAR              = 5
477    XINE_META_INFO_VIDEOCODEC        = 6
478    XINE_META_INFO_AUDIOCODEC        = 7
479    XINE_META_INFO_SYSTEMLAYER       = 8
480    XINE_META_INFO_INPUT_PLUGIN      = 9
481
482    def get_meta_info(self, info):
483        return xinelib.xine_get_meta_info(self.__stream_p, info)
484
485    XINE_STREAM_INFO_BITRATE         = 0
486    XINE_STREAM_INFO_SEEKABLE        = 1
487    XINE_STREAM_INFO_VIDEO_WIDTH     = 2
488    XINE_STREAM_INFO_VIDEO_HEIGHT    = 3
489    XINE_STREAM_INFO_VIDEO_RATIO     = 4
490
491    def get_stream_info(self, info):
492        return xinelib.xine_get_stream_info(self.__stream_p, info)
493
494    XINE_LANG_MAX = 256
495
496    def get_audio_lang(self, channel):
497        _lang = ctypes.create_string_buffer(Stream.XINE_LANG_MAX)
498
499        result = xinelib.xine_get_audio_lang(self.__stream_p, channel, _lang)
500        if not result:
501            _lang.raw = 'unknown'
502
503        return _lang.value
504
505    def get_spu_lang(self, channel):
506        _lang = ctypes.create_string_buffer(Stream.XINE_LANG_MAX)
507
508        result = xinelib.xine_get_spu_lang(self.__stream_p, channel, _lang)
509        if not result:
510            _lang.raw = 'unknown'
511
512        return _lang.value
513
514    def set_dpms(self, activated):
515        if self.__video_port:
516            self.__video_port.display.set_dpms(activated)
517
518    def osd_new(self, font_size):
519        if not self.__video_port:
520            raise XineError('This Stream is audio only.')
521
522        # Does this need locking the video area?
523        self.__osd = Osd(self,
524                         self.__video_port.window.video_area_info['width'],
525                         self.__video_port.window.video_area_info['height'])
526        self.__osd.set_font('sans', font_size)
527        self.__osd.set_text_palette(\
528                                   Osd.XINE_TEXTPALETTE_WHITE_BLACK_TRANSPARENT,
529                                   Osd.XINE_OSD_TEXT1)
530        return self.__osd
531
532    def close(self):
533        self.stop()
534        xinelib.xine_close(self.__stream_p)
535
536    def destroy(self):
537        self.close()
538        self.set_param(Stream.XINE_PARAM_AUDIO_CLOSE_DEVICE, 1)
539
540        if self.__event_queue:
541            self.__event_queue.close()
542            self.__event_queue = None
543        if self.__osd:
544            self.__osd.close()
545            self.__osd = None
546
547        xinelib.xine_dispose(self.__stream_p)
548        self.__stream_p = None
549
550        self.__audio_port.destroy()
551        self.__audio_port = None
552        if self.__video_port:
553            self.__video_port.destroy()
554            self.__video_port = None
555
556
557class XinePlayer(object):
558
559    XINE_MSG_NO_ERROR              = 0 # (messages to UI)
560    XINE_MSG_GENERAL_WARNING       = 1 # (warning message)
561    XINE_MSG_UNKNOWN_HOST          = 2 # (host name)
562    XINE_MSG_UNKNOWN_DEVICE        = 3 # (device name)
563    XINE_MSG_NETWORK_UNREACHABLE   = 4 # none
564    XINE_MSG_CONNECTION_REFUSED    = 5 # (host name)
565    XINE_MSG_FILE_NOT_FOUND        = 6 # (file name or mrl)
566    XINE_MSG_READ_ERROR            = 7 # (device/file/mrl)
567    XINE_MSG_LIBRARY_LOAD_ERROR    = 8 # (library/decoder)
568    XINE_MSG_ENCRYPTED_SOURCE      = 9 # none
569    XINE_MSG_SECURITY              = 10 # (security message)
570    XINE_MSG_AUDIO_OUT_UNAVAILABLE = 11 # none
571    XINE_MSG_PERMISSION_ERROR      = 12 # (file name or mrl)
572    XINE_MSG_FILE_EMPTY            = 13 # file is empty
573
574    def __init__(self, config_file_path=None):
575        self.__xine = xinelib.xine_new()
576        if not self.__xine:
577            raise XineError('Error during Xine instance initialisation')
578
579        if config_file_path:
580            xinelib.xine_config_load(self.__xine, config_file_path)
581        else: # load default config file
582            default = os.path.join(xinelib.xine_get_homedir(),".xine/config")
583            xinelib.xine_config_load(self.__xine, default)
584
585        xinelib.xine_init(self.__xine)
586
587    def xine_p(self):
588        return self.__xine
589
590    def get_version(self):
591        major = ctypes.c_int()
592        minor = ctypes.c_int()
593        sub = ctypes.c_int()
594        xinelib.xine_get_version(ctypes.byref(major),
595                                 ctypes.byref(minor),
596                                 ctypes.byref(sub))
597        return (major.value, minor.value, sub.value)
598
599    def has_gapless(self):
600        return xinelib.xine_check_version(1, 1, 1) == 1
601
602    def get_supported_extensions(self):
603        return xinelib.xine_get_file_extensions(self.__xine).split()
604
605    def list_input_plugins(self):
606        plugins = []
607        for plugin in xinelib.xine_list_input_plugins(self.__xine):
608            if not plugin:
609                break
610            plugins.append(plugin.lower())
611        return plugins
612
613    def destroy(self):
614        xinelib.xine_exit(self.__xine)
615        self.__xine = None
616
617    XINE_ENGINE_PARAM_VERBOSITY_NONE = 0
618    XINE_ENGINE_PARAM_VERBOSITY_LOG =  1
619
620    def set_param(self, param, value):
621        xinelib.xine_engine_set_param(self.__xine, param, value)
622
623    def stream_new(self, audio_port=None, video_port=None, video=False):
624        if video and not video_port:
625            video_port = VideoDriver(self)
626        return Stream(self, audio_port, video_port)
627
628
629if __name__ == '__main__':
630    import sys, os, time
631    x = XinePlayer(os.path.expanduser('~/.xine/config'))
632    print 'Xine %d.%d.%d ' % x.get_version()
633    x.set_param(XinePlayer.XINE_ENGINE_PARAM_VERBOSITY_LOG, 1)
634    vd = VideoDriver(x, fullscreen=False)
635    s = x.stream_new(video_port=vd)
636
637    def print_message(data, event):
638        if event.type == Event.XINE_EVENT_UI_MESSAGE:
639            try:
640                print "Xine error message : %s" % event.message()
641            except XineError, e:
642                print "Xine exception message : %s " % e
643    s.add_event_callback(print_message)
644
645    file_path = sys.argv[1]
646    if not file_path.startswith('/') and not file_path.startswith('http://'):
647       file_path = os.path.join(os.getcwd(), file_path)
648    if file_path.startswith('/'):
649       file_path = 'file:/' + file_path
650    s.open(file_path)
651    s.play()
652    time.sleep(15)
653    s.stop()
654    s.destroy()
655    x.destroy()
656
657
658# vim: ts=4 sw=4 expandtab
Note: See TracBrowser for help on using the browser.