~joni-noplu/elisa/deinterlacing_support

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.