From: Krzesimir Nowak Date: Mon, 12 Dec 2011 15:02:01 +0000 (+0100) Subject: core: Append extensions to served files X-Git-Tag: RYGEL_0_13_1~23 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=674800ee11e09c8477c69f6bb76decae06496c37;p=profile%2Fivi%2Frygel.git core: Append extensions to served files --- 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 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 (); + // 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 subtitles = new ArrayList (); public ArrayList thumbnails = new ArrayList (); + public ArrayList uris = new ArrayList (); 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 uris = new ArrayList (); + public string mime_type; +} + +private class Rygel.Thumbnail { + public string file_extension; +} + +private class Rygel.VisualItem : MediaItem { + public ArrayList thumbnails = new ArrayList (); +} + +private class Rygel.Subtitle : GLib.Object { + public string caption_type; +} + +private class Rygel.VideoItem : VisualItem { + public ArrayList subtitles = new ArrayList (); } 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 uris = new ArrayList (); 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 thumbnails = new ArrayList (); + + public VisualItem () { + base.for_visual_item(); + } +} + +private class Rygel.Subtitle : GLib.Object { + public string caption_type; +} + +private class Rygel.VideoItem : Rygel.VisualItem { + public ArrayList subtitles = new ArrayList (); +} 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; + } +}