[rygel] core: Append extensions to served files



commit 674800ee11e09c8477c69f6bb76decae06496c37
Author: Krzesimir Nowak <qdlacz gmail com>
Date:   Mon Dec 12 16:02:01 2011 +0100

    core: Append extensions to served files

 src/rygel/rygel-aac-transcoder.vala   |    2 +-
 src/rygel/rygel-audio-transcoder.vala |   10 ++-
 src/rygel/rygel-avc-transcoder.vala   |    1 +
 src/rygel/rygel-http-item-uri.vala    |  125 ++++++++++++++++++++++++++++++++-
 src/rygel/rygel-http-server.vala      |    2 +-
 src/rygel/rygel-l16-transcoder.vala   |    3 +-
 src/rygel/rygel-mp2ts-transcoder.vala |    1 +
 src/rygel/rygel-mp3-transcoder.vala   |    3 +-
 src/rygel/rygel-transcoder.vala       |    5 +-
 src/rygel/rygel-video-transcoder.vala |    4 +-
 src/rygel/rygel-wmv-transcoder.vala   |    3 +-
 tests/rygel-http-get-test.vala        |   32 +++++++--
 tests/rygel-http-item-uri-test.vala   |   60 ++++++++++++++--
 tests/rygel-http-post-test.vala       |   46 ++++++++++++-
 14 files changed, 268 insertions(+), 29 deletions(-)
---
diff --git a/src/rygel/rygel-aac-transcoder.vala b/src/rygel/rygel-aac-transcoder.vala
index 805ad18..71f74fa 100644
--- a/src/rygel/rygel-aac-transcoder.vala
+++ b/src/rygel/rygel-aac-transcoder.vala
@@ -33,6 +33,6 @@ internal class Rygel.AACTranscoder : Rygel.AudioTranscoder {
                                  "channels=1";
 
     public AACTranscoder () {
-        base ("audio/3gpp", "AAC_ISO_320", BITRATE, CONTAINER, CODEC);
+        base ("audio/3gpp", "AAC_ISO_320", BITRATE, CONTAINER, CODEC, "3gp");
     }
 }
diff --git a/src/rygel/rygel-audio-transcoder.vala b/src/rygel/rygel-audio-transcoder.vala
index 0b45be5..eead824 100644
--- a/src/rygel/rygel-audio-transcoder.vala
+++ b/src/rygel/rygel-audio-transcoder.vala
@@ -36,8 +36,9 @@ internal class Rygel.AudioTranscoder : Rygel.Transcoder {
                             string  dlna_profile,
                             int     audio_bitrate,
                             string? container_caps,
-                            string  audio_codec_caps) {
-        base (content_type, dlna_profile, AudioItem.UPNP_CLASS);
+                            string  audio_codec_caps,
+                            string  extension) {
+        base (content_type, dlna_profile, AudioItem.UPNP_CLASS, extension);
 
         this.audio_bitrate = audio_bitrate;
         if (container_caps != null) {
@@ -52,8 +53,9 @@ internal class Rygel.AudioTranscoder : Rygel.Transcoder {
                                        string  upnp_class,
                                        int     audio_bitrate,
                                        string? container_caps,
-                                       string  audio_codec_caps) {
-        base (content_type, dlna_profile, upnp_class);
+                                       string  audio_codec_caps,
+                                       string  extension) {
+        base (content_type, dlna_profile, upnp_class, extension);
 
         this.audio_bitrate = audio_bitrate;
         if (container_caps != null) {
diff --git a/src/rygel/rygel-avc-transcoder.vala b/src/rygel/rygel-avc-transcoder.vala
index d2651df..cb4dbe8 100644
--- a/src/rygel/rygel-avc-transcoder.vala
+++ b/src/rygel/rygel-avc-transcoder.vala
@@ -45,6 +45,7 @@ internal class Rygel.AVCTranscoder : Rygel.VideoTranscoder {
               CONTAINER,
               AUDIO_CAPS,
               VIDEO_CAPS,
+              "mp4",
               RESTRICTIONS);
     }
 
diff --git a/src/rygel/rygel-http-item-uri.vala b/src/rygel/rygel-http-item-uri.vala
index 861a6ea..0e48b8d 100644
--- a/src/rygel/rygel-http-item-uri.vala
+++ b/src/rygel/rygel-http-item-uri.vala
@@ -23,23 +23,97 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+using Gee;
+
 internal class Rygel.HTTPItemURI : Object {
     public string item_id;
     public int thumbnail_index;
     public int subtitle_index;
     public string? transcode_target;
     public unowned HTTPServer http_server;
+    private string real_extension;
+    public string extension {
+        owned get {
+            if (this.real_extension != "") {
+                return "." + this.real_extension;
+            }
+            return "";
+        }
+        set {
+            this.real_extension = value;
+        }
+    }
 
-    public HTTPItemURI (string     item_id,
+    public static HashMap<string, string> mime_to_ext;
+
+    public HTTPItemURI (MediaItem  item,
                         HTTPServer http_server,
                         int        thumbnail_index = -1,
                         int        subtitle_index = -1,
                         string?    transcode_target = null) {
-        this.item_id = item_id;
+        this.item_id = item.id;
         this.thumbnail_index = thumbnail_index;
         this.subtitle_index = subtitle_index;
         this.transcode_target = transcode_target;
         this.http_server = http_server;
+        this.extension = "";
+
+        if (thumbnail_index > -1) {
+            if (item is VisualItem) {
+                var thumbnails = (item as VisualItem).thumbnails;
+
+                if (thumbnails.size > thumbnail_index) {
+                    this.extension = thumbnails[thumbnail_index].file_extension;
+                } else {
+                    this.extension = "jpg";
+                    // what now? throw an error?
+                }
+            } else {
+                this.extension = "jpg";
+                // what now? throw an error?
+            }
+        }
+        else if (subtitle_index > -1) {
+            if (item is VideoItem) {
+                var subtitles = (item as VideoItem).subtitles;
+
+                if (subtitles.size > subtitle_index) {
+                    this.extension = subtitles[subtitle_index].caption_type;
+                } else {
+                    // what now? throw an error?
+                    this.extension = "srt";
+                }
+            } else {
+                // what now? throw an error?
+                this.extension = "srt";
+            }
+        }
+        else if (transcode_target != null) {
+            try {
+                var tc = this.http_server.get_transcoder (transcode_target);
+
+                this.extension = tc.extension;
+            } catch (Error err) {}
+        }
+        if (this.extension == "") {
+            string uri_extension = "";
+
+            foreach (string uri_string in item.uris) {
+                string basename = Path.get_basename (uri_string);
+                int dot_index = basename.last_index_of(".");
+
+                if (dot_index > -1) {
+                    uri_extension = basename.substring (dot_index + 1);
+                    break;
+                }
+            }
+
+            if (uri_extension == "") {
+                this.extension = ext_from_mime_type (item.mime_type);
+            } else {
+                this.extension = uri_extension;
+            }
+        }
     }
 
     public HTTPItemURI.from_string (string     uri,
@@ -50,6 +124,7 @@ internal class Rygel.HTTPItemURI : Object {
         this.subtitle_index = -1;
         this.transcode_target = null;
         this.http_server = http_server;
+        this.extension = "";
 
         var request_uri = uri.replace (http_server.path_root, "");
         var parts = request_uri.split ("/");
@@ -59,6 +134,14 @@ internal class Rygel.HTTPItemURI : Object {
                                                     request_uri);
         }
 
+        string last_part = parts[parts.length - 1];
+        int dot_index = last_part.last_index_of (".");
+
+        if (dot_index > -1) {
+            this.extension = last_part.substring (dot_index + 1);
+            parts[parts.length - 1] = last_part.substring (0, dot_index);
+        }
+
         for (int i = 1; i < parts.length - 1; i += 2) {
             switch (parts[i]) {
                 case "i":
@@ -108,7 +191,7 @@ internal class Rygel.HTTPItemURI : Object {
         } else if (this.subtitle_index >= 0) {
             path += "/sub/" + this.subtitle_index.to_string ();
         }
-
+        path += this.extension;
         return this.create_uri_for_path (path);
     }
 
@@ -118,4 +201,40 @@ internal class Rygel.HTTPItemURI : Object {
                                           this.http_server.path_root,
                                           path);
     }
+
+    private string ext_from_mime_type (string mime_type) {
+        if (mime_to_ext == null) {
+            mime_to_ext = new HashMap<string, string> ();
+            // videos
+            string[] videos = {"mpeg", "webm", "ogg"};
+
+            foreach (string video in videos) {
+                mime_to_ext.set ("video/" + video, video);
+            }
+            mime_to_ext.set("video/x-matroska", "mkv");
+
+            // audios
+            mime_to_ext.set ("audio/x-wav", "wav");
+            mime_to_ext.set ("audio/x-matroska", "mka");
+
+            // images
+            string[] images = {"jpeg", "png"};
+
+            foreach (string image in images) {
+                mime_to_ext.set ("image/" + image, image);
+            }
+
+            // texts
+            mime_to_ext.set ("text/srt", "srt");
+
+            // applications? (can be either video or audio?);
+            mime_to_ext.set ("application/ogg", "ogg");
+        }
+
+        if (this.mime_to_ext.has_key (mime_type)) {
+            return mime_to_ext.get (mime_type);
+        }
+
+        return "";
+    }
 }
diff --git a/src/rygel/rygel-http-server.vala b/src/rygel/rygel-http-server.vala
index 1b49b5f..bbfa083 100644
--- a/src/rygel/rygel-http-server.vala
+++ b/src/rygel/rygel-http-server.vala
@@ -100,7 +100,7 @@ internal class Rygel.HTTPServer : Rygel.TranscodeManager, Rygel.StateMachine {
                                                   int       thumbnail_index,
                                                   int       subtitle_index,
                                                   string?   transcode_target) {
-        var uri = new HTTPItemURI (item.id,
+        var uri = new HTTPItemURI (item,
                                    this,
                                    thumbnail_index,
                                    subtitle_index,
diff --git a/src/rygel/rygel-l16-transcoder.vala b/src/rygel/rygel-l16-transcoder.vala
index e9e0c77..54516f5 100644
--- a/src/rygel/rygel-l16-transcoder.vala
+++ b/src/rygel/rygel-l16-transcoder.vala
@@ -52,7 +52,8 @@ internal class Rygel.L16Transcoder : Rygel.AudioTranscoder {
               "LPCM",
               0,
               AudioTranscoder.NO_CONTAINER,
-              caps_str);
+              caps_str,
+              "lpcm");
     }
 
     public override DIDLLiteResource? add_resource (DIDLLiteItem     didl_item,
diff --git a/src/rygel/rygel-mp2ts-transcoder.vala b/src/rygel/rygel-mp2ts-transcoder.vala
index a0609e1..06708fd 100644
--- a/src/rygel/rygel-mp2ts-transcoder.vala
+++ b/src/rygel/rygel-mp2ts-transcoder.vala
@@ -63,6 +63,7 @@ internal class Rygel.MP2TSTranscoder : Rygel.VideoTranscoder {
               CONTAINER,
               AUDIO_FORMAT,
               BASE_VIDEO_FORMAT,
+              "mpg",
               RESTRICTION_TEMPLATE.printf (FRAME_RATE[profile],
                                            WIDTH[profile],
                                            HEIGHT[profile]));
diff --git a/src/rygel/rygel-mp3-transcoder.vala b/src/rygel/rygel-mp3-transcoder.vala
index 6eb7206..ad14a3b 100644
--- a/src/rygel/rygel-mp3-transcoder.vala
+++ b/src/rygel/rygel-mp3-transcoder.vala
@@ -36,6 +36,7 @@ internal class Rygel.MP3Transcoder : Rygel.AudioTranscoder {
               "MP3",
               BITRATE,
               AudioTranscoder.NO_CONTAINER,
-              FORMAT);
+              FORMAT,
+              "mp3");
     }
 }
diff --git a/src/rygel/rygel-transcoder.vala b/src/rygel/rygel-transcoder.vala
index 2e7b28e..63a71b2 100644
--- a/src/rygel/rygel-transcoder.vala
+++ b/src/rygel/rygel-transcoder.vala
@@ -31,6 +31,7 @@ using GUPnP;
 internal abstract class Rygel.Transcoder : GLib.Object {
     public string mime_type { get; protected set; }
     public string dlna_profile { get; protected set; }
+    public string extension { get; protected set; }
 
     private const string DECODE_BIN = "decodebin2";
     private const string ENCODE_BIN = "encodebin";
@@ -46,11 +47,13 @@ internal abstract class Rygel.Transcoder : GLib.Object {
 
     public Transcoder (string mime_type,
                        string dlna_profile,
-                       string upnp_class) {
+                       string upnp_class,
+                       string extension) {
         this.mime_type = mime_type;
         this.dlna_profile = dlna_profile;
         this.upnp_class = upnp_class;
         this.link_failed = true;
+        this.extension = extension;
     }
 
     /**
diff --git a/src/rygel/rygel-video-transcoder.vala b/src/rygel/rygel-video-transcoder.vala
index 0639cab..15f1928 100644
--- a/src/rygel/rygel-video-transcoder.vala
+++ b/src/rygel/rygel-video-transcoder.vala
@@ -37,6 +37,7 @@ internal class Rygel.VideoTranscoder : Rygel.AudioTranscoder {
                             string  container_caps,
                             string  audio_codec_caps,
                             string  video_codec_caps,
+                            string  extension,
                             string? restrictions = null) {
 
         base.with_class (content_type,
@@ -44,7 +45,8 @@ internal class Rygel.VideoTranscoder : Rygel.AudioTranscoder {
                          VideoItem.UPNP_CLASS,
                          audio_bitrate,
                          container_caps,
-                         audio_codec_caps);
+                         audio_codec_caps,
+                         extension);
 
         this.video_bitrate = video_bitrate;
         this.video_codec_format = Caps.from_string (video_codec_caps);
diff --git a/src/rygel/rygel-wmv-transcoder.vala b/src/rygel/rygel-wmv-transcoder.vala
index a601ddc..947ee04 100644
--- a/src/rygel/rygel-wmv-transcoder.vala
+++ b/src/rygel/rygel-wmv-transcoder.vala
@@ -33,6 +33,7 @@ internal class Rygel.WMVTranscoder : Rygel.VideoTranscoder {
               VIDEO_BITRATE,
               "video/x-ms-asf,parsed=true",
               "audio/x-wma,channels=2,wmaversion=1",
-              "video/x-wmv,wmvversion=1");
+              "video/x-wmv,wmvversion=1",
+              "wmv");
     }
 }
diff --git a/tests/rygel-http-get-test.vala b/tests/rygel-http-get-test.vala
index 9b5912c..f9632ff 100644
--- a/tests/rygel-http-get-test.vala
+++ b/tests/rygel-http-get-test.vala
@@ -132,7 +132,7 @@ public class Rygel.HTTPGetTest : GLib.Object {
         requests.add (new TestRequestFactory (request, Soup.KnownStatusCode.OK));
 
         string uri = this.server.create_uri ("VideoItem");
-        uri = uri + "/tr/MPEG";
+        uri = uri + "/tr/MP3";
         request = new Soup.Message ("HEAD", uri);
         requests.add (new TestRequestFactory (request, Soup.KnownStatusCode.OK));
 
@@ -261,10 +261,13 @@ public class Rygel.HTTPServer : GLib.Object {
         }
     }
 
-    public string create_uri(string item_id) {
-            var item_uri = new HTTPItemURI (item_id,
-                                            this);
-            return item_uri.to_string ();
+    public string create_uri (string item_id) {
+        var item = new VideoItem ();
+        item.id = item_id;
+
+        var item_uri = new HTTPItemURI (item, this);
+
+        return item_uri.to_string ();
     }
 
     public signal void message_received (Soup.Message message);
@@ -295,7 +298,12 @@ public class Rygel.HTTPServer : GLib.Object {
     }
 
     public Transcoder get_transcoder (string target) throws Error {
-        return new Transcoder ();
+        if (target == "MP3") {
+            return new Transcoder ("mp3");
+        }
+        throw new HTTPRequestError.NOT_FOUND (
+                            "No transcoder available for target format '%s'",
+                            target);
     }
 }
 
@@ -368,6 +376,7 @@ public abstract class Rygel.MediaItem : Rygel.MediaObject {
     public long size = 1024;
     public ArrayList<Subtitle> subtitles = new ArrayList<Subtitle> ();
     public ArrayList<Thumbnail> thumbnails = new ArrayList<Thumbnail> ();
+    public ArrayList<string> uris = new ArrayList<string> ();
 
     public bool place_holder = false;
 
@@ -441,10 +450,12 @@ private class Rygel.MusicItem : AudioItem {
 
 public class Rygel.Thumbnail {
     public long size = 1024;
+    public string file_extension;
 }
 
 public class Rygel.Subtitle {
     public long size = 1024;
+    public string caption_type;
 }
 
 internal class Rygel.HTTPResponse : Rygel.StateMachine, GLib.Object {
@@ -479,6 +490,13 @@ internal class Rygel.HTTPResponse : Rygel.StateMachine, GLib.Object {
 
 public class Rygel.MediaObject {
     public string id;
+    public string mime_type = "";
 }
 
-public class Rygel.Transcoder {}
+public class Rygel.Transcoder : GLib.Object {
+    public string extension { get; protected set; }
+
+    public Transcoder (string extension) {
+        this.extension = extension;
+    }
+}
diff --git a/tests/rygel-http-item-uri-test.vala b/tests/rygel-http-item-uri-test.vala
index f79295a..e527156 100644
--- a/tests/rygel-http-item-uri-test.vala
+++ b/tests/rygel-http-item-uri-test.vala
@@ -21,6 +21,8 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+using Gee;
+
 private errordomain Rygel.HTTPRequestError {
     UNACCEPTABLE = Soup.KnownStatusCode.NOT_ACCEPTABLE,
     BAD_REQUEST = Soup.KnownStatusCode.BAD_REQUEST,
@@ -31,6 +33,14 @@ private errordomain Rygel.TestError {
     SKIP
 }
 
+private class Rygel.Transcoder : GLib.Object {
+    public string extension { get; protected set; }
+
+    public Transcoder (string extension) {
+        this.extension = extension;
+    }
+}
+
 private class Rygel.HTTPServer : GLib.Object {
     private const string SERVER_PATH = "/Test";
 
@@ -51,14 +61,44 @@ private class Rygel.HTTPServer : GLib.Object {
         assert (this.context.host_ip != null);
         assert (this.context.port > 0);
     }
+
+    public Transcoder get_transcoder (string  target) throws Error {
+        if (target == "MP3") {
+            return new Transcoder ("mp3");
+        }
+        throw new HTTPRequestError.NOT_FOUND (
+                            "No transcoder available for target format '%s'",
+                            target);
+    }
+}
+
+private class Rygel.MediaItem : GLib.Object {
+    public string id;
+    public ArrayList<string> uris = new ArrayList<string> ();
+    public string mime_type;
+}
+
+private class Rygel.Thumbnail {
+    public string file_extension;
+}
+
+private class Rygel.VisualItem : MediaItem {
+    public ArrayList<Thumbnail> thumbnails = new ArrayList<Thumbnail> ();
+}
+
+private class Rygel.Subtitle : GLib.Object {
+    public string caption_type;
+}
+
+private class Rygel.VideoItem : VisualItem {
+    public ArrayList<Subtitle> subtitles = new ArrayList<Subtitle> ();
 }
 
 private class Rygel.HTTPItemURITest : GLib.Object {
-    private const string ITEM_ID = "HELLO";
     private const int THUMBNAIL_INDEX = 1;
     private const int SUBTITLE_INDEX = 1;
     private const string TRANSCODE_TARGET = "MP3";
-
+    private VisualItem item = new VisualItem ();
     private HTTPServer server;
 
     public static int main (string[] args) {
@@ -78,6 +118,14 @@ private class Rygel.HTTPItemURITest : GLib.Object {
     }
 
     public void run () throws Error {
+        Thumbnail thumb = new Thumbnail ();
+
+        thumb.file_extension = "png";
+        this.item.thumbnails.add (thumb);
+        this.item.id = "HELLO";
+        this.item.uris.add ("foo.mp3");
+        this.item.mime_type = "audio/mp3";
+
         var uris = new HTTPItemURI[] {
             this.test_construction (),
             this.test_construction_with_thumbnail (),
@@ -96,14 +144,14 @@ private class Rygel.HTTPItemURITest : GLib.Object {
     }
 
     private HTTPItemURI test_construction () {
-        var uri = new HTTPItemURI (ITEM_ID, this.server);
+        var uri = new HTTPItemURI (this.item, this.server);
         assert (uri != null);
 
         return uri;
     }
 
     private HTTPItemURI test_construction_with_subtitle () {
-        var uri = new HTTPItemURI (ITEM_ID,
+        var uri = new HTTPItemURI (this.item,
                                    this.server,
                                    -1,
                                    SUBTITLE_INDEX);
@@ -113,7 +161,7 @@ private class Rygel.HTTPItemURITest : GLib.Object {
     }
 
     private HTTPItemURI test_construction_with_thumbnail () {
-        var uri = new HTTPItemURI (ITEM_ID,
+        var uri = new HTTPItemURI (this.item,
                                    this.server,
                                    THUMBNAIL_INDEX);
         assert (uri != null);
@@ -122,7 +170,7 @@ private class Rygel.HTTPItemURITest : GLib.Object {
     }
 
     private HTTPItemURI test_construction_with_transcoder () {
-        var uri = new HTTPItemURI (ITEM_ID,
+        var uri = new HTTPItemURI (this.item,
                                    this.server,
                                    THUMBNAIL_INDEX,
                                    -1,
diff --git a/tests/rygel-http-post-test.vala b/tests/rygel-http-post-test.vala
index 7abdf87..531f3a4 100644
--- a/tests/rygel-http-post-test.vala
+++ b/tests/rygel-http-post-test.vala
@@ -170,7 +170,7 @@ public class Rygel.HTTPServer : GLib.Object {
 
     public string uri {
         owned get {
-            var item_uri = new HTTPItemURI (this.root_container.ITEM_ID,
+            var item_uri = new HTTPItemURI (this.root_container.item,
                                             this);
 
             return item_uri.to_string ();
@@ -204,6 +204,15 @@ public class Rygel.HTTPServer : GLib.Object {
     private void on_got_headers (Soup.Message msg) {
         this.message_received (msg);
     }
+
+    public Transcoder get_transcoder (string target) throws Error {
+        if (target == "MP3") {
+            return new Transcoder ("mp3");
+        }
+        throw new HTTPRequestError.NOT_FOUND (
+                            "No transcoder available for target format '%s'",
+                            target);
+    }
 }
 
 public class Rygel.HTTPClient : GLib.Object, StateMachine {
@@ -293,11 +302,14 @@ public class Rygel.MediaItem : Rygel.MediaObject {
     public string id;
     public long size = 1024;
     public long duration = 1024;
+    public ArrayList<string> uris = new ArrayList<string> ();
 
     public bool place_holder = true;
 
     public File file;
 
+    public MediaItem.for_visual_item () {}
+
     public MediaItem (string id, MediaContainer parent) {
         this.id = id;
         this.parent = parent;
@@ -373,8 +385,38 @@ public class Rygel.ItemRemovalQueue: GLib.Object {
     }
 }
 
-public class Rygel.MediaObject : GLib.Object {}
+public class Rygel.MediaObject : GLib.Object {
+    public string mime_type = "";
+}
+
+public class Rygel.Thumbnail : GLib.Object {
+    public string file_extension;
+}
+
+public class Rygel.VisualItem : Rygel.MediaItem {
+    public ArrayList<Thumbnail> thumbnails = new ArrayList<Thumbnail> ();
+
+    public VisualItem () {
+        base.for_visual_item();
+    }
+}
+
+private class Rygel.Subtitle : GLib.Object {
+    public string caption_type;
+}
+
+private class Rygel.VideoItem : Rygel.VisualItem {
+    public ArrayList<Subtitle> subtitles = new ArrayList<Subtitle> ();
+}
 
 public errordomain Rygel.ContentDirectoryError {
     INVALID_ARGS = 402
 }
+
+public class Rygel.Transcoder : GLib.Object {
+    public string extension { get; protected set; }
+
+    public Transcoder (string extension) {
+        this.extension = extension;
+    }
+}



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