using Invercargill; namespace Ppub { public class VideoManifest { public const string TITLE = "title"; public const string AUTHOR = "author"; public const string COPYRIGHT = "copyright"; public const string LICENCE = "licence"; public const string MASTER = "master"; public const string POSTER = "poster"; public const string RATIO = "ratio"; public const string DURATION = "duration"; public const string DESCRIPTION_ASSET = "description"; public const string VIDEO = "video"; private Gee.HashMap entries { get; set; } public Invercargill.Sequence streams { get; set; } public VideoManifest() { entries = new Gee.HashMap(); streams = Invercargill.empty().to_sequence(); } public string? get_value(string name) { if (entries.has_key(name)) { return entries.get(name); } return null; } public void set_value(string name, string value) { entries.set(name, value); } public string? title { owned get { return get_value(TITLE); } set { set_value(TITLE, value); } } public string? author { owned get { return get_value(AUTHOR); } set { set_value(AUTHOR, value); } } public string? copyright { owned get { return get_value(COPYRIGHT); } set { set_value(COPYRIGHT, value); } } public string? licence { owned get { return get_value(LICENCE); } set { set_value(LICENCE, value); } } public string? master { owned get { return get_value(MASTER); } set { set_value(MASTER, value); } } public string? poster { owned get { return get_value(POSTER); } set { set_value(POSTER, value); } } public double[]? ratio { owned get { var ratio = get_value(RATIO); if(ratio == null) { return null; } var ratio_data = ratio.split(":", 2); return new double[] { double.parse(ratio_data[0]), double.parse(ratio_data[1]) }; } set { set_value(RATIO, @"$(value[0]):$(value[1])"); } } public double? duration { owned get { var duration = get_value(DURATION); if(duration == null) { return null; } return double.parse(duration); } set { set_value(DURATION, value.to_string()); } } public string? description_file_name { owned get { return get_value(DESCRIPTION_ASSET); } set { set_value(DESCRIPTION_ASSET, value); } } public VideoManifest.from_stream(InputStream stream) throws IOError { var dis = new DataInputStream(stream); entries = new Gee.HashMap(); streams = new Invercargill.Sequence(); var metadata_complete = false; string line = dis.read_line(); if(line != "PPVM") { throw new IOError.INVALID_DATA("Stream does not begin with PPVM magic number"); } while((line = dis.read_line()) != null) { if(line.chomp().chug() == "") { metadata_complete = true; continue; } var kv = line.split(": ", 2); if(!metadata_complete) { print(@"[Stream reader] Property $(kv[0]) is $(kv[1])\n"); entries.set(kv[0], kv[1]); } else { if(kv[0] == VIDEO) { streams.add(new VideoDescription.from_string(kv[1])); } } } } public string to_string() { var data = "PPVM\n"; foreach (var key in entries.keys) { data += @"$key: $(entries[key])\n"; } data += "\n"; foreach (var stream in streams) { data += @"$VIDEO: $(stream.to_string())\n"; } data += "\n"; return data; } } public class VideoDescription { public string version_label {get; set;} public string file_name {get; set;} public const string SIZE = "size"; public const string CODECS = "codecs"; private Gee.HashMap properties { get; set; } public VideoDescription() { properties = new Gee.HashMap(); } public VideoDescription.from_string(string line) { var fields = line.split(", ", 3); version_label = fields[0]; file_name = fields[1]; properties = new Gee.HashMap(); var property_items = fields[2].split(";"); foreach (var item in property_items) { if(item.chomp().chug() == ""){ continue; } var item_parts = item.split("=\"", 2); var name = item_parts[0].chomp().chug(); var value = item_parts[1].split("\"")[0]; print(@"prop: $(name) = $(value)\n"); properties.set(name, value); } } public string to_string() { var meta = ""; foreach(var key in properties.keys) { meta += @" $key=\"$(properties[key])\";"; } return @"$version_label, $file_name,$meta"; } public string? get_property(string name) { if (properties.has_key(name)) { return properties.get(name); } return null; } public void set_property(string name, string value) { properties.set(name, value); } public string? codecs { owned get { return get_property(CODECS); } set { set_property(CODECS, value); } } public string? size { owned get { return get_property(SIZE); } set { set_property(SIZE, value); } } } }