1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
# -*- coding: utf-8 -*-
# Moovida - Home multimedia server
# Copyright (C) 2006-2009 Fluendo Embedded S.L. (www.fluendo.com).
# All rights reserved.
#
# This file is available under one of two license agreements.
#
# This file is licensed under the GPL version 3.
# See "LICENSE.GPL" in the root of this distribution including a special
# exception to use Moovida with Fluendo's plugins.
#
# The GPL part of Moovida is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Moovida" in the root directory of this distribution package
# for details on that license.
#
# Author: Olivier Tilloy <olivier@fluendo.com>
"""
Common models related to media.
"""
from elisa.core.components.model import Model
from elisa.core.utils import defer, notifying_list
import gobject
class PlayableModel(Model):
"""
A playable model contains the real URI of a playable media, that is,
typically, a URI directly usable by gstreamer to play streamed data.
It also potentially contains a title for the media. If the title
is not set, any read access to that property will return the
filename of the uri instance attribute.
@ivar uri: the real URI of the playable media
@type uri: L{elisa.core.media_uri.MediaUri}
@ivar title: the title of the playable media
@type title: C{unicode}
@ivar allow_pause: whether the player can pause the media playback or not
@type allow_pause: C{bool}
@ivar allow_seek: whether the player can seek inside the media playback or not
@type allow_seek: C{bool}
@ivar source_properties: the properties of the source element of the
GStreamer pipeline for this playable media
@type source_properties: C{dict} of C{unicode} keys and values
"""
def __init__(self):
"""
Constructor. Initialize all the fields.
"""
super(PlayableModel, self).__init__()
self.uri = None
self.title = None
self.allow_pause = True
self.allow_seek = True
self.deinterlace = False
self.source_properties = {}
def __eq__(self, other):
"""
Compare two playable models.
Two playable models are considered equal if and only if their URIs are
equal.
@param other: another playable model
@type other: L{elisa.plugins.base.models.media.PlayableModel}
@return: C{True} if the two models are equal, C{False} otherwise
@rtype: C{bool}
"""
return (self.uri == other.uri)
def title_set(self, title):
self._title = title
def titlet_get(self):
title = self._title
if (not title) and self.uri:
title = self.uri.filename
return title
title = property(fset=title_set,fget=titlet_get)
class PlaylistModel(Model, notifying_list.List):
"""
A playlist model is a list of models that can be played by
a player. The models stored in this list *must* implement the
get_playable_model method, like
L{elisa.plugins.base.models.audio.TrackModel} and
L{elisa.plugins.base.models.video.VideoModel}.
@ivar allow_previous: if it is possible to set as current the previous track
in the playlist relatively to the current one by
calling the method 'previous_track'
@type allow_previous: C{bool}
@ivar allow_next: if it is possible to set as current the next track
in the playlist relatively to the current one by
calling the method 'next_track'
@type allow_next: C{bool}
@ivar allow_jump: if it is possible to set as current any track knowing its
index in the playlist by calling the method
'set_current_index'
@type allow_jump: C{bool}
@ivar current_playable_model: playable model corresponding to the current
track in the playlist; it differs from the model
stored in the playlist because it is not the model
itself but only the shell containing the necessary
playback information
@type current_playable_model: L{elisa.plugins.base.models.media.PlayableModel}
@ivar current_model: a model (video, track etc.) corresponding to the
current track in the playlist; it points to one of the
models in the playlist itself
@type current_model: C{elisa.core.components.model.Model}
@ivar current_index: index in the playlist of the current model being played
@type current_index: C{int}
"""
gobject.signal_new('current-model-changed',
notifying_list.Notifier,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_PYOBJECT,))
gobject.signal_new('current-playable-model-changed',
notifying_list.Notifier,
gobject.SIGNAL_RUN_LAST,
gobject.TYPE_NONE,
(gobject.TYPE_PYOBJECT,))
def __init__(self):
"""
Constructor. Initialize all the fields.
"""
super(PlaylistModel, self).__init__()
self.allow_previous = True
self.allow_next = True
self.allow_jump = True
self.current_model = None
self.current_playable_model = None
self.current_index = -1
def previous_track(self):
"""
Decrement L{current_index} of the playlist and return the
PlayableModel located at the new position in the playlist.
@rtype: L{twisted.internet.defer.Deferred}
"""
if self.current_index > 0:
dfr = self.set_current_index(self.current_index-1)
else:
dfr = defer.fail(Exception("Beginning of playlist reached"))
return dfr
def next_track(self):
"""
Increment L{current_index} of the playlist and return the
PlayableModel located at the new position in the playlist.
@rtype: L{twisted.internet.defer.Deferred}
"""
if self.current_index < len(self)-1:
dfr = self.set_current_index(self.current_index+1)
else:
dfr = defer.fail(Exception("End of playlist reached"))
return dfr
def set_current_index(self, index):
"""
Set L{current_index} of the playlist and return the
PlayableModel located at the new position in the playlist.
@rtype: L{twisted.internet.defer.Deferred}
"""
def got_playable_model(model):
self.current_playable_model = model
self.notifier.emit('current-playable-model-changed', model)
return model
self.current_index = index
self.current_model = self[index]
self.notifier.emit('current-model-changed', self[index])
dfr = self._retrieve_playable_model_at(index)
dfr.addCallback(got_playable_model)
return dfr
def _retrieve_playable_model_at(self, index):
track = self[index]
if not isinstance(track, PlayableModel):
dfr = track.get_playable_model()
else:
dfr = defer.succeed(track)
return dfr
class RawDataModel(Model):
"""
A raw data model contains raw data from a media file (can be binary, text,
etc...).
@ivar data: the raw data
@type data: C{str}
@ivar size: the total size of the data
@type size: C{int}
"""
def __init__(self):
"""
Constructor. Initialize all the fields.
"""
super(RawDataModel, self).__init__()
self.data = None
self.size = None
# TODO: subclass the RawDataModel to have a model that reads its data
# asynchronously.
|