From 4d9b1428e8df65da170b895f3bd981f65caf09e7 Mon Sep 17 00:00:00 2001 From: "Zeeshan Ali (Khattak)" Date: Sun, 6 Sep 2009 02:44:11 +0300 Subject: [PATCH] core: Allow plugins to provide thumbnails Plugins can now provide thumnails using a new easy-to-use API. --- src/rygel/Makefile.am | 1 + src/rygel/rygel-http-identity-handler.vala | 40 ++++++++++++---- src/rygel/rygel-http-request.vala | 12 +++++ src/rygel/rygel-http-server.vala | 29 ++++++++++-- src/rygel/rygel-media-item.vala | 12 +++++ src/rygel/rygel-thumbnail.vala | 76 ++++++++++++++++++++++++++++++ src/rygel/rygel-transcode-manager.vala | 1 + src/rygel/rygel-transcoder.vala | 1 + 8 files changed, 160 insertions(+), 12 deletions(-) create mode 100644 src/rygel/rygel-thumbnail.vala diff --git a/src/rygel/Makefile.am b/src/rygel/Makefile.am index e9e289e..85d42a3 100644 --- a/src/rygel/Makefile.am +++ b/src/rygel/Makefile.am @@ -66,6 +66,7 @@ VAPI_SOURCE_FILES = rygel-configuration.vala \ rygel-media-container.vala \ rygel-simple-async-result.vala \ rygel-media-item.vala \ + rygel-thumbnail.vala \ rygel-browse.vala \ rygel-didl-lite-writer.vala \ rygel-transcoder.vala \ diff --git a/src/rygel/rygel-http-identity-handler.vala b/src/rygel/rygel-http-identity-handler.vala index e473927..ec46794 100644 --- a/src/rygel/rygel-http-identity-handler.vala +++ b/src/rygel/rygel-http-identity-handler.vala @@ -30,20 +30,30 @@ internal class Rygel.HTTPIdentityHandler : Rygel.HTTPRequestHandler { public override void add_response_headers (HTTPRequest request) throws HTTPRequestError { - var item = request.item; + long size; + string mime_type; - request.msg.response_headers.append ("Content-Type", item.mime_type); - if (item.size >= 0) { - request.msg.response_headers.set_content_length (item.size); + if (request.thumbnail != null) { + size = request.thumbnail.size; + mime_type= request.thumbnail.mime_type; + } else { + size = request.item.size; + mime_type= request.item.mime_type; } - if (item.should_stream ()) { + + request.msg.response_headers.append ("Content-Type", mime_type); + if (size >= 0) { + request.msg.response_headers.set_content_length (size); + } + + if (request.thumbnail == null && request.item.should_stream ()) { if (request.time_range != null) { request.time_range.add_response_header (request.msg); } } else { request.msg.response_headers.append ("Accept-Ranges", "bytes"); if (request.byte_range != null) { - request.byte_range.add_response_header (request.msg, item.size); + request.byte_range.add_response_header (request.msg, size); } } @@ -53,6 +63,14 @@ internal class Rygel.HTTPIdentityHandler : Rygel.HTTPRequestHandler { public override HTTPResponse render_body (HTTPRequest request) throws HTTPRequestError { + if (request.thumbnail != null) { + return new SeekableResponse (request.server, + request.msg, + request.thumbnail.uri, + request.byte_range, + request.thumbnail.size); + } + var item = request.item; if (item.should_stream ()) { @@ -84,8 +102,12 @@ internal class Rygel.HTTPIdentityHandler : Rygel.HTTPRequestHandler { protected override DIDLLiteResource add_resource (DIDLLiteItem didl_item, HTTPRequest request) throws HTTPRequestError { - return request.item.add_resource (didl_item, - null, - request.http_server.get_protocol ()); + var protocol = request.http_server.get_protocol (); + + if (request.thumbnail != null) { + return request.thumbnail.add_resource (didl_item, protocol); + } else { + return request.item.add_resource (didl_item, null, protocol); + } } } diff --git a/src/rygel/rygel-http-request.vala b/src/rygel/rygel-http-request.vala index 580d11c..2299d7f 100644 --- a/src/rygel/rygel-http-request.vala +++ b/src/rygel/rygel-http-request.vala @@ -44,7 +44,9 @@ internal class Rygel.HTTPRequest : GLib.Object, Rygel.StateMachine { private HTTPResponse response; private string item_id; + private int thumbnail_index; public MediaItem item; + public Thumbnail thumbnail; public HTTPSeek byte_range; public HTTPSeek time_range; @@ -61,6 +63,7 @@ internal class Rygel.HTTPRequest : GLib.Object, Rygel.StateMachine { this.server = server; this.msg = msg; this.query = query; + this.thumbnail_index = -1; } public void run (Cancellable? cancellable) { @@ -86,6 +89,11 @@ internal class Rygel.HTTPRequest : GLib.Object, Rygel.StateMachine { var transcoder = this.http_server.get_transcoder (target); this.request_handler = new HTTPTranscodeHandler (transcoder); } + + var index = this.query.lookup ("thumbnail"); + if (index != null) { + this.thumbnail_index = index.to_int (); + } } if (this.item_id == null) { @@ -151,6 +159,10 @@ internal class Rygel.HTTPRequest : GLib.Object, Rygel.StateMachine { this.item = (MediaItem) media_object; + if (this.thumbnail_index >= 0) { + this.thumbnail = this.item.thumbnails.get (this.thumbnail_index); + } + this.handle_item_request (); } diff --git a/src/rygel/rygel-http-server.vala b/src/rygel/rygel-http-server.vala index d583aac..0d06b7e 100644 --- a/src/rygel/rygel-http-server.vala +++ b/src/rygel/rygel-http-server.vala @@ -67,11 +67,29 @@ internal class Rygel.HTTPServer : Rygel.TranscodeManager, Rygel.StateMachine { if (!this.http_uri_present (item)) { // Create the HTTP proxy URI string protocol; - var uri = this.create_uri_for_item (item, null, out protocol); + var uri = this.create_uri_for_item (item, -1, null, out protocol); item.add_resource (didl_item, uri, protocol); } base.add_resources (didl_item, item); + + // Thumbnails comes in the end + foreach (var thumbnail in item.thumbnails) { + if (!is_http_uri (thumbnail.uri)) { + var uri = thumbnail.uri; // Save the original URI + var index = item.thumbnails.index_of (thumbnail); + string protocol; + + thumbnail.uri = this.create_uri_for_item (item, + index, + null, + out protocol); + thumbnail.add_resource (didl_item, protocol); + + // Now restore the original URI + thumbnail.uri = uri; + } + } } private bool http_uri_present (MediaItem item) { @@ -104,11 +122,16 @@ internal class Rygel.HTTPServer : Rygel.TranscodeManager, Rygel.StateMachine { path); } - internal override string create_uri_for_item (MediaItem item, - string? transcode_target, + internal override string create_uri_for_item (MediaItem item, + int thumbnail_index, + string? transcode_target, out string protocol) { string escaped = Uri.escape_string (item.id, "", true); string query = "?itemid=" + escaped; + if (thumbnail_index >= 0) { + query += "&thumbnail=" + thumbnail_index.to_string (); + } + if (transcode_target != null) { escaped = Uri.escape_string (transcode_target, "", true); query += "&transcode=" + escaped; diff --git a/src/rygel/rygel-media-item.vala b/src/rygel/rygel-media-item.vala index 1e2e2d1..40dcca7 100644 --- a/src/rygel/rygel-media-item.vala +++ b/src/rygel/rygel-media-item.vala @@ -63,6 +63,8 @@ public class Rygel.MediaItem : MediaObject { public int pixel_height = -1; public int color_depth = -1; + public ArrayList thumbnails; + public MediaItem (string id, MediaContainer parent, string title, @@ -71,6 +73,8 @@ public class Rygel.MediaItem : MediaObject { this.parent = parent; this.title = title; this.upnp_class = upnp_class; + + this.thumbnails = new ArrayList (); } // Live media items need to provide a nice working implementation of this @@ -117,6 +121,14 @@ public class Rygel.MediaItem : MediaObject { this.add_resource (didl_item, uri, protocol); } } + + foreach (var thumbnail in this.thumbnails) { + var protocol = this.get_protocol_for_uri (thumbnail.uri); + + if (allow_internal || protocol != "internal") { + thumbnail.add_resource (didl_item, protocol); + } + } } internal DIDLLiteResource add_resource (DIDLLiteItem didl_item, diff --git a/src/rygel/rygel-thumbnail.vala b/src/rygel/rygel-thumbnail.vala new file mode 100644 index 0000000..63f5e7d --- /dev/null +++ b/src/rygel/rygel-thumbnail.vala @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008 Zeeshan Ali . + * + * Author: Zeeshan Ali + * + * This file is part of Rygel. + * + * Rygel is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Rygel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using GUPnP; + +private errordomain Rygel.ThumbnailError { + BAD_URI +} + +/** + * Represents a picture or video thumbnail. + */ +public class Rygel.Thumbnail : GLib.Object { + public string uri; + public string mime_type; + public string dlna_profile; + + public long size = -1; // Size in bytes + public int width = -1; // Width in pixels + public int height = -1; // Height in pixels + public int color_depth = -1; // depth of pixels in bytes + + public Thumbnail (string mime_type = "image/jpeg", + string dlna_profile = "JPEG_TN") { + this.mime_type = mime_type; + this.dlna_profile = dlna_profile; + } + + internal DIDLLiteResource add_resource (DIDLLiteItem didl_item, + string protocol) { + var res = didl_item.add_resource (); + + res.uri = this.uri; + res.size = this.size; + + res.width = this.width; + res.height = this.height; + res.color_depth = this.color_depth; + + /* Protocol info */ + res.protocol_info = this.get_protocol_info (protocol); + + return res; + } + + private ProtocolInfo get_protocol_info (string protocol) { + var protocol_info = new ProtocolInfo (); + + protocol_info.mime_type = this.mime_type; + protocol_info.dlna_profile = this.dlna_profile; + protocol_info.protocol = protocol; + protocol_info.dlna_flags |= DLNAFlags.INTERACTIVE_TRANSFER_MODE | + DLNAFlags.BACKGROUND_TRANSFER_MODE; + + return protocol_info; + } +} diff --git a/src/rygel/rygel-transcode-manager.vala b/src/rygel/rygel-transcode-manager.vala index fe15db8..5bb002e 100644 --- a/src/rygel/rygel-transcode-manager.vala +++ b/src/rygel/rygel-transcode-manager.vala @@ -53,6 +53,7 @@ internal abstract class Rygel.TranscodeManager : GLib.Object { } public abstract string create_uri_for_item (MediaItem item, + int thumbnail_index, string? transcode_target, out string protocol); diff --git a/src/rygel/rygel-transcoder.vala b/src/rygel/rygel-transcoder.vala index f13a313..d16d4ca 100644 --- a/src/rygel/rygel-transcoder.vala +++ b/src/rygel/rygel-transcoder.vala @@ -66,6 +66,7 @@ internal abstract class Rygel.Transcoder : GLib.Object { string protocol; var uri = manager.create_uri_for_item (item, + -1, this.dlna_profile, out protocol); var res = item.add_resource (didl_item, uri, protocol); -- 2.7.4