[rygel] server: Refactor subtitle handling



commit 3d777ecc385d38c6c6787314058b2f076a174f1e
Author: Jens Georg <mail jensge org>
Date:   Sun Feb 8 11:27:28 2015 +0100

    server: Refactor subtitle handling
    
    Based on Cablelabs's CVP-2 implementation.
    
    Signed-off-by: Jens Georg <mail jensge org>

 src/librygel-server/filelist.am                    |    1 +
 src/librygel-server/rygel-http-byte-seek.vala      |    2 +-
 src/librygel-server/rygel-http-get.vala            |    8 +-
 .../rygel-http-identity-handler.vala               |   18 +---
 .../rygel-http-subtitle-handler.vala               |  102 ++++++++++++++++++++
 src/librygel-server/rygel-http-time-seek.vala      |    2 +-
 src/librygel-server/rygel-video-item.vala          |   79 ++++++++-------
 7 files changed, 153 insertions(+), 59 deletions(-)
---
diff --git a/src/librygel-server/filelist.am b/src/librygel-server/filelist.am
index 29ce50a..395f826 100644
--- a/src/librygel-server/filelist.am
+++ b/src/librygel-server/filelist.am
@@ -44,6 +44,7 @@ LIBRYGEL_SERVER_NONVAPI_SOURCE_FILES = \
        rygel-http-get-handler.vala \
        rygel-http-get.vala \
        rygel-http-thumbnail-handler.vala \
+       rygel-http-subtitle-handler.vala \
        rygel-http-identity-handler.vala \
        rygel-http-item-uri.vala \
        rygel-http-post.vala \
diff --git a/src/librygel-server/rygel-http-byte-seek.vala b/src/librygel-server/rygel-http-byte-seek.vala
index 76cb361..df1f2cc 100644
--- a/src/librygel-server/rygel-http-byte-seek.vala
+++ b/src/librygel-server/rygel-http-byte-seek.vala
@@ -72,7 +72,7 @@ internal class Rygel.HTTPByteSeek : Rygel.HTTPSeek {
                 ((request.object as MediaFileItem).size > 0 &&
                 request.handler is HTTPIdentityHandler) ||
                 (request.handler is HTTPThumbnailHandler) ||
-               (request.subtitle != null && request.subtitle.size > 0));
+                (request.handler is HTTPSubtitleHandler));
     }
 
     public static bool requested (HTTPGet request) {
diff --git a/src/librygel-server/rygel-http-get.vala b/src/librygel-server/rygel-http-get.vala
index 0e7f602..60a2c74 100644
--- a/src/librygel-server/rygel-http-get.vala
+++ b/src/librygel-server/rygel-http-get.vala
@@ -70,12 +70,14 @@ internal class Rygel.HTTPGet : HTTPRequest {
             this.handler = new HTTPMediaResourceHandler (this.object,
                                                          uri.resource_name,
                                                          this.cancellable);
-        }
-
-        if (uri.thumbnail_index >= 0) {
+        } else if (uri.thumbnail_index >= 0) {
             this.handler = new HTTPThumbnailHandler (this.object as MediaFileItem,
                                                      uri.thumbnail_index,
                                                      this.cancellable);
+        } else if (uri.subtitle_index >= 0) {
+            this.handler = new HTTPSubtitleHandler (this.object as MediaFileItem,
+                                                    uri.subtitle_index,
+                                                    this.cancellable);
         }
 
         if (this.handler == null) {
diff --git a/src/librygel-server/rygel-http-identity-handler.vala 
b/src/librygel-server/rygel-http-identity-handler.vala
index 383f057..8563c28 100644
--- a/src/librygel-server/rygel-http-identity-handler.vala
+++ b/src/librygel-server/rygel-http-identity-handler.vala
@@ -34,10 +34,7 @@ internal class Rygel.HTTPIdentityHandler : Rygel.HTTPGetHandler {
 
     public override void add_response_headers (HTTPGet request)
                                                throws HTTPRequestError {
-        if (request.subtitle != null) {
-           request.msg.response_headers.append ("Content-Type",
-                                                request.subtitle.mime_type);
-        } else {
+        {
             request.msg.response_headers.append ("Content-Type",
                                                  (request.object as MediaFileItem).mime_type);
         }
@@ -90,15 +87,8 @@ internal class Rygel.HTTPIdentityHandler : Rygel.HTTPGetHandler {
     }
 
     private HTTPResponse render_body_real (HTTPGet request) throws Error {
-        DataSource src;
-        var engine = MediaEngine.get_default ();
-
-        if (request.subtitle != null) {
-            src = engine.create_data_source (request.subtitle.uri);
-        } else {
-            src = (request.object as MediaFileItem).create_stream_source
+        var src = (request.object as MediaFileItem).create_stream_source
                                         (request.http_server.context.host_ip);
-        }
 
         if (src == null) {
             throw new HTTPRequestError.NOT_FOUND (_("Not found"));
@@ -108,10 +98,6 @@ internal class Rygel.HTTPIdentityHandler : Rygel.HTTPGetHandler {
     }
 
     private int64 get_size (HTTPGet request) {
-        if (request.subtitle != null) {
-            return request.subtitle.size;
-        }
-
         return (request.object as MediaFileItem).size;
     }
 }
diff --git a/src/librygel-server/rygel-http-subtitle-handler.vala 
b/src/librygel-server/rygel-http-subtitle-handler.vala
new file mode 100644
index 0000000..383b468
--- /dev/null
+++ b/src/librygel-server/rygel-http-subtitle-handler.vala
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2008, 2009 Nokia Corporation.
+ * Copyright (C) 2012 Intel Corporation.
+ * Copyright (C) 2013  Cable Television Laboratories, Inc.
+ *
+ * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
+ *                               <zeeshan ali nokia com>
+ *         Jens Georg <jensg openismus com>
+ *         Craig Pratt <craig ecaspia com>
+ *
+ * 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;
+
+internal class Rygel.HTTPSubtitleHandler : Rygel.HTTPGetHandler {
+    private MediaFileItem media_item;
+    private int subtitle_index;
+    public Subtitle subtitle;
+
+    public HTTPSubtitleHandler (MediaFileItem media_item,
+                                int subtitle_index,
+                                Cancellable? cancellable) throws HTTPRequestError {
+        this.media_item = media_item;
+        this.subtitle_index = subtitle_index;
+        this.cancellable = cancellable;
+
+        if (subtitle_index >= 0 && media_item is VideoItem) {
+            var video_item = media_item as VideoItem;
+
+            if (subtitle_index < video_item.subtitles.size) {
+                this.subtitle = video_item.subtitles.get (subtitle_index);
+            }
+        }
+
+        if (this.subtitle == null) {
+            throw new HTTPRequestError.NOT_FOUND ("Subtitle index %d not found for item '%s",
+                                                  subtitle_index, media_item.id);
+        }
+    }
+
+    public override bool supports_transfer_mode (string mode) {
+        // Support interactive and background transfers only
+        return (mode != TRANSFER_MODE_STREAMING);
+    }
+
+    public override void add_response_headers (HTTPGet request)
+                                               throws HTTPRequestError {
+        // Add Content-Type
+        request.msg.response_headers.append ("Content-Type", subtitle.mime_type);
+
+        // Add contentFeatures.dlna.org
+
+        // This is functionally equivalent to how contentFeatures was formed via the
+        //  (deprecated) HTTPIdentityHandler
+        MediaResource res = this.media_item.get_resource_list ().get (0);
+        string protocol_info = res.get_protocol_info ().to_string ();
+        var pi_fields = protocol_info.split (":", 4);
+        request.msg.response_headers.append ("contentFeatures.dlna.org", pi_fields[3]);
+
+        // Chain-up
+        base.add_response_headers (request);
+    }
+
+    public override HTTPResponse render_body (HTTPGet request)
+                                              throws HTTPRequestError {
+        DataSource src;
+        try {
+            var engine = MediaEngine.get_default ();
+            src = engine.create_data_source (this.subtitle.uri);
+
+            return new HTTPResponse (request, this, src);
+        } catch (Error err) {
+            throw new HTTPRequestError.NOT_FOUND (err.message);
+        }
+    }
+
+    public override int64 get_resource_size () {
+        return subtitle.size;
+    }
+
+    protected override DIDLLiteResource add_resource
+                                        (DIDLLiteObject didl_object,
+                                         HTTPGet        request)
+                                         throws Error {
+        return null as DIDLLiteResource;
+    }
+}
diff --git a/src/librygel-server/rygel-http-time-seek.vala b/src/librygel-server/rygel-http-time-seek.vala
index a829079..7967bf5 100644
--- a/src/librygel-server/rygel-http-time-seek.vala
+++ b/src/librygel-server/rygel-http-time-seek.vala
@@ -101,7 +101,7 @@ internal class Rygel.HTTPTimeSeek : Rygel.HTTPSeek {
                (request.object as AudioItem).duration > 0 &&
                (request.handler is HTTPTranscodeHandler ||
                 (!(request.handler is HTTPThumbnailHandler) &&
-                 request.subtitle == null &&
+                 !(request.handler is HTTPSubtitleHandler) &&
                  (request.object as MediaFileItem).is_live_stream ())));
     }
 
diff --git a/src/librygel-server/rygel-video-item.vala b/src/librygel-server/rygel-video-item.vala
index e59eb85..ad625e5 100644
--- a/src/librygel-server/rygel-video-item.vala
+++ b/src/librygel-server/rygel-video-item.vala
@@ -142,62 +142,65 @@ public class Rygel.VideoItem : AudioItem, VisualItem {
     internal override DIDLLiteObject? serialize (Serializer serializer,
                                                  HTTPServer  http_server)
                                                  throws Error {
-        var didl_item = base.serialize (serializer, http_server);
+        var didl_item = base.serialize (serializer, http_server) as DIDLLiteItem;
 
         if (this.author != null && this.author != "") {
             var contributor = didl_item.add_author ();
             contributor.name = this.author;
         }
 
-        return didl_item;
-    }
-
-    internal override void add_proxy_resources (HTTPServer   server,
-                                                DIDLLiteItem didl_item)
-                                                throws Error {
-        var main_subtitle = null as Subtitle;
         if (!this.place_holder) {
-            // Subtitles first
+            var main_subtitle = null as Subtitle;
             foreach (var subtitle in this.subtitles) {
-                if (!server.need_proxy (subtitle.uri)) {
-                    if (main_subtitle == null) {
-                        main_subtitle = subtitle;
-                    }
-
+                string protocol;
+                try {
+                    protocol = this.get_protocol_for_uri (subtitle.uri);
+                } catch (Error e) {
+                    message ("Could not determine protocol for " + subtitle.uri);
                     continue;
                 }
 
-                var uri = subtitle.uri; // Save the original URI
-                var index = this.subtitles.index_of (subtitle);
+                if (http_server.need_proxy (subtitle.uri)) {
+                    var uri = subtitle.uri; // Save the original URI
+                    var index = this.subtitles.index_of (subtitle);
 
-                subtitle.uri = server.create_uri_for_object (this,
-                                                             -1,
-                                                             index,
-                                                             null,
-                                                             null);
-                subtitle.add_didl_node (didl_item);
+                    subtitle.uri = http_server.create_uri_for_object (this,
+                                                                      -1,
+                                                                      index,
+                                                                      null,
+                                                                      null);
+                    subtitle.add_didl_node (didl_item);
+                    subtitle.uri = uri; // Now restore the original URI
 
-                if (main_subtitle == null) {
-                    main_subtitle = new Subtitle (subtitle.mime_type,
-                                                  subtitle.caption_type);
-                    main_subtitle.uri = subtitle.uri;
+                    if (main_subtitle == null) {
+                        main_subtitle = new Subtitle (subtitle.mime_type,
+                                                      subtitle.caption_type);
+                        main_subtitle.uri = uri;
+                    }
+                } else if (main_subtitle == null) {
+                    main_subtitle = subtitle;
                 }
 
-                // Now restore the original URI
-                subtitle.uri = uri;
+                if (http_server.is_local () || protocol != "internal") {
+                    subtitle.add_didl_node (didl_item);
+                }
             }
-        }
-
-        base.add_proxy_resources (server, didl_item);
-
-        if (main_subtitle != null) {
-            var resources = didl_item.get_resources ();
-            foreach (var resource in resources) {
-                resource.subtitle_file_type =
-                    main_subtitle.caption_type.up ();
-                resource.subtitle_file_uri = main_subtitle.uri;
+            if (main_subtitle != null) {
+                // Add resource-level subtitle metadata to all streamable video resources
+                // Note: All resources have already been serialized by the base
+                var resources = didl_item.get_resources ();
+                foreach (var resource in resources) {
+                    if ( (resource.protocol_info.dlna_flags
+                          & DLNAFlags.STREAMING_TRANSFER_MODE) != 0) {
+                        resource.subtitle_file_type =
+                            main_subtitle.caption_type.up ();
+                        resource.subtitle_file_uri = main_subtitle.uri;
+                    }
+                }
             }
         }
+
+        return didl_item;
     }
 
     internal override void add_additional_resources (HTTPServer server) {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]