2
* Copyright (C) 2008 Zeeshan Ali <zeenix@gmail.com>.
4
* Author: Zeeshan Ali <zeenix@gmail.com>
6
* This file is part of Rygel.
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.
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.
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.
27
private errordomain Rygel.MediaItemError {
32
* Represents a media (Music, Video and Image) item.
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";
43
public string upnp_class;
46
public string mime_type;
47
public string dlna_profile;
49
public long size = -1; // Size in bytes
50
public long duration = -1; // Duration in seconds
51
public int bitrate = -1; // Bytes/second
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;
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;
66
public ArrayList<Thumbnail> thumbnails;
68
public MediaItem (string id,
69
MediaContainer parent,
75
this.upnp_class = upnp_class;
77
this.thumbnails = new ArrayList<Thumbnail> ();
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;
85
if (this.uris.size != 0) {
86
src = Element.make_from_uri (URIType.SRC, this.uris.get (0), null);
89
if (src != null && src.get_type ().name () == "GstRTSPSrc") {
90
// For rtspsrc since some RTSP sources takes a while to start
92
src.tcp_timeout = (int64) 60000000;
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
101
public virtual bool should_stream () {
102
// Simple heuristic: if we know the size, serve directly.
103
return this.size <= 0;
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) {
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 ();
119
if (thumbnailer == null) {
124
var thumb = thumbnailer.get_thumbnail (uri);
125
this.thumbnails.add (thumb);
126
} catch (Error err) {}
130
internal int compare_transcoders (void *a, void *b) {
131
var transcoder1 = (Transcoder) a;
132
var transcoder2 = (Transcoder) b;
134
return (int) transcoder1.get_distance (this) -
135
(int) transcoder2.get_distance (this);
138
internal void add_resources (DIDLLiteItem didl_item,
141
foreach (var uri in this.uris) {
142
var protocol = this.get_protocol_for_uri (uri);
144
if (allow_internal || protocol != "internal") {
145
this.add_resource (didl_item, uri, protocol);
149
foreach (var thumbnail in this.thumbnails) {
150
var protocol = this.get_protocol_for_uri (thumbnail.uri);
152
if (allow_internal || protocol != "internal") {
153
thumbnail.add_resource (didl_item, protocol);
158
internal DIDLLiteResource add_resource (DIDLLiteItem didl_item,
162
var res = didl_item.add_resource ();
168
res.size = this.size;
169
res.duration = this.duration;
170
res.bitrate = this.bitrate;
172
res.sample_freq = this.sample_freq;
173
res.bits_per_sample = this.bits_per_sample;
174
res.audio_channels = this.n_audio_channels;
176
res.width = this.width;
177
res.height = this.height;
178
res.color_depth = this.color_depth;
181
res.protocol_info = this.get_protocol_info (uri, protocol);
186
private ProtocolInfo get_protocol_info (string? uri,
188
var protocol_info = new ProtocolInfo ();
190
protocol_info.mime_type = this.mime_type;
191
protocol_info.dlna_profile = this.dlna_profile;
192
protocol_info.protocol = protocol;
194
if (this.upnp_class.has_prefix (MediaItem.IMAGE_CLASS)) {
195
protocol_info.dlna_flags |= DLNAFlags.INTERACTIVE_TRANSFER_MODE;
197
protocol_info.dlna_flags |= DLNAFlags.STREAMING_TRANSFER_MODE;
200
if (!this.should_stream ()) {
201
protocol_info.dlna_operation = DLNAOperation.RANGE;
202
protocol_info.dlna_flags |= DLNAFlags.BACKGROUND_TRANSFER_MODE;
205
return protocol_info;
208
private string get_protocol_for_uri (string uri) throws Error {
209
if (uri.has_prefix ("http")) {
211
} else if (uri.has_prefix ("file")) {
213
} else if (uri.has_prefix ("rtsp")) {
214
// FIXME: Assuming that RTSP is always accompanied with RTP over UDP
215
return "rtsp-rtp-udp";
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);
223
warning ("Failed to probe protocol for URI %s. Assuming '%s'",