~ubuntu-branches/ubuntu/precise/rygel/precise

« back to all changes in this revision

Viewing changes to src/rygel/rygel-media-item.vala

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Henriksson
  • Date: 2009-09-26 14:04:05 UTC
  • Revision ID: james.westby@ubuntu.com-20090926140405-d5x3j13k10psa1gu
Tags: upstream-0.4.1
ImportĀ upstreamĀ versionĀ 0.4.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>.
 
3
 *
 
4
 * Author: Zeeshan Ali <zeenix@gmail.com>
 
5
 *
 
6
 * This file is part of Rygel.
 
7
 *
 
8
 * Rygel is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU Lesser General Public License as published by
 
10
 * the Free Software Foundation; either version 2 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * Rygel is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU Lesser General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Lesser General Public License
 
19
 * along with this program; if not, write to the Free Software Foundation,
 
20
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
21
 */
 
22
 
 
23
using GUPnP;
 
24
using Gee;
 
25
using Gst;
 
26
 
 
27
private errordomain Rygel.MediaItemError {
 
28
    BAD_URI
 
29
}
 
30
 
 
31
/**
 
32
 * Represents a media (Music, Video and Image) item.
 
33
 */
 
34
public class Rygel.MediaItem : MediaObject {
 
35
    public static const string IMAGE_CLASS = "object.item.imageItem";
 
36
    public static const string VIDEO_CLASS = "object.item.videoItem";
 
37
    public static const string AUDIO_CLASS = "object.item.audioItem";
 
38
    public static const string MUSIC_CLASS = "object.item.audioItem.musicTrack";
 
39
 
 
40
    public string author;
 
41
    public string album;
 
42
    public string date;
 
43
    public string upnp_class;
 
44
 
 
45
    // Resource info
 
46
    public string mime_type;
 
47
    public string dlna_profile;
 
48
 
 
49
    public long size = -1;       // Size in bytes
 
50
    public long duration = -1;   // Duration in seconds
 
51
    public int bitrate = -1;     // Bytes/second
 
52
 
 
53
    // Audio/Music
 
54
    public int sample_freq = -1;
 
55
    public int bits_per_sample = -1;
 
56
    public int n_audio_channels = -1;
 
57
    public int track_number = -1;
 
58
 
 
59
    // Image/Video
 
60
    public int width = -1;
 
61
    public int height = -1;
 
62
    public int pixel_width = -1;
 
63
    public int pixel_height = -1;
 
64
    public int color_depth = -1;
 
65
 
 
66
    public ArrayList<Thumbnail> thumbnails;
 
67
 
 
68
    public MediaItem (string         id,
 
69
                      MediaContainer parent,
 
70
                      string         title,
 
71
                      string         upnp_class) {
 
72
        this.id = id;
 
73
        this.parent = parent;
 
74
        this.title = title;
 
75
        this.upnp_class = upnp_class;
 
76
 
 
77
        this.thumbnails = new ArrayList<Thumbnail> ();
 
78
    }
 
79
 
 
80
    // Live media items need to provide a nice working implementation of this
 
81
    // method if they can/do not provide a valid URI
 
82
    public virtual Element? create_stream_source () {
 
83
        dynamic Element src = null;
 
84
 
 
85
        if (this.uris.size != 0) {
 
86
            src = Element.make_from_uri (URIType.SRC, this.uris.get (0), null);
 
87
        }
 
88
 
 
89
        if (src != null && src.get_type ().name () == "GstRTSPSrc") {
 
90
            // For rtspsrc since some RTSP sources takes a while to start
 
91
            // transmitting
 
92
            src.tcp_timeout = (int64) 60000000;
 
93
        }
 
94
 
 
95
        return src;
 
96
    }
 
97
 
 
98
    // Return true if item should be streamed as a live response with
 
99
    // time based seeking, or false to serve directly with byte range
 
100
    // seeking.
 
101
    public virtual bool should_stream () {
 
102
        // Simple heuristic: if we know the size, serve directly.
 
103
        return this.size <= 0;
 
104
    }
 
105
 
 
106
    // Adds URI to MediaItem. You can either provide the associated thumbnail or
 
107
    // ask Rygel to try to fetch it for you by passing null as @thumbnail.
 
108
    public void add_uri (string     uri,
 
109
                         Thumbnail? thumbnail) {
 
110
        this.uris.add (uri);
 
111
 
 
112
        if (thumbnail != null) {
 
113
            this.thumbnails.add (thumbnail);
 
114
        } else if (this.upnp_class.has_prefix (MediaItem.IMAGE_CLASS) ||
 
115
                   this.upnp_class.has_prefix (MediaItem.VIDEO_CLASS)) {
 
116
            // Lets see if we can provide the thumbnails
 
117
            var thumbnailer = Thumbnailer.get_default ();
 
118
 
 
119
            if (thumbnailer == null) {
 
120
                return;
 
121
            }
 
122
 
 
123
            try {
 
124
                var thumb = thumbnailer.get_thumbnail (uri);
 
125
                this.thumbnails.add (thumb);
 
126
            } catch (Error err) {}
 
127
        }
 
128
    }
 
129
 
 
130
    internal int compare_transcoders (void *a, void *b) {
 
131
        var transcoder1 = (Transcoder) a;
 
132
        var transcoder2 = (Transcoder) b;
 
133
 
 
134
        return (int) transcoder1.get_distance (this) -
 
135
               (int) transcoder2.get_distance (this);
 
136
    }
 
137
 
 
138
    internal void add_resources (DIDLLiteItem didl_item,
 
139
                                 bool         allow_internal)
 
140
                                 throws Error {
 
141
        foreach (var uri in this.uris) {
 
142
            var protocol = this.get_protocol_for_uri (uri);
 
143
 
 
144
            if (allow_internal || protocol != "internal") {
 
145
                this.add_resource (didl_item, uri, protocol);
 
146
            }
 
147
        }
 
148
 
 
149
        foreach (var thumbnail in this.thumbnails) {
 
150
            var protocol = this.get_protocol_for_uri (thumbnail.uri);
 
151
 
 
152
            if (allow_internal || protocol != "internal") {
 
153
                thumbnail.add_resource (didl_item, protocol);
 
154
            }
 
155
        }
 
156
    }
 
157
 
 
158
    internal DIDLLiteResource add_resource (DIDLLiteItem didl_item,
 
159
                                            string?      uri,
 
160
                                            string       protocol)
 
161
                                            throws Error {
 
162
        var res = didl_item.add_resource ();
 
163
 
 
164
        if (uri != null) {
 
165
            res.uri = uri;
 
166
        }
 
167
 
 
168
        res.size = this.size;
 
169
        res.duration = this.duration;
 
170
        res.bitrate = this.bitrate;
 
171
 
 
172
        res.sample_freq = this.sample_freq;
 
173
        res.bits_per_sample = this.bits_per_sample;
 
174
        res.audio_channels = this.n_audio_channels;
 
175
 
 
176
        res.width = this.width;
 
177
        res.height = this.height;
 
178
        res.color_depth = this.color_depth;
 
179
 
 
180
        /* Protocol info */
 
181
        res.protocol_info = this.get_protocol_info (uri, protocol);
 
182
 
 
183
        return res;
 
184
    }
 
185
 
 
186
    private ProtocolInfo get_protocol_info (string? uri,
 
187
                                            string  protocol) {
 
188
        var protocol_info = new ProtocolInfo ();
 
189
 
 
190
        protocol_info.mime_type = this.mime_type;
 
191
        protocol_info.dlna_profile = this.dlna_profile;
 
192
        protocol_info.protocol = protocol;
 
193
 
 
194
        if (this.upnp_class.has_prefix (MediaItem.IMAGE_CLASS)) {
 
195
            protocol_info.dlna_flags |= DLNAFlags.INTERACTIVE_TRANSFER_MODE;
 
196
        } else {
 
197
            protocol_info.dlna_flags |= DLNAFlags.STREAMING_TRANSFER_MODE;
 
198
        }
 
199
 
 
200
        if (!this.should_stream ()) {
 
201
            protocol_info.dlna_operation = DLNAOperation.RANGE;
 
202
            protocol_info.dlna_flags |= DLNAFlags.BACKGROUND_TRANSFER_MODE;
 
203
        }
 
204
 
 
205
        return protocol_info;
 
206
    }
 
207
 
 
208
    private string get_protocol_for_uri (string uri) throws Error {
 
209
        if (uri.has_prefix ("http")) {
 
210
            return "http-get";
 
211
        } else if (uri.has_prefix ("file")) {
 
212
            return "internal";
 
213
        } else if (uri.has_prefix ("rtsp")) {
 
214
            // FIXME: Assuming that RTSP is always accompanied with RTP over UDP
 
215
            return "rtsp-rtp-udp";
 
216
        } else {
 
217
            // Assume the protocol to be the scheme of the URI
 
218
            var tokens = uri.split (":", 2);
 
219
            if (tokens[0] == null) {
 
220
                throw new MediaItemError.BAD_URI ("Bad URI: %s", uri);
 
221
            }
 
222
 
 
223
            warning ("Failed to probe protocol for URI %s. Assuming '%s'",
 
224
                     uri,
 
225
                     tokens[0]);
 
226
 
 
227
            return tokens[0];
 
228
        }
 
229
    }
 
230
}