public VLCWrapperParsingUnit(string identifier, Reference <WebTranscodingInfo> save, WebMediaInfo info, long position) { this.identifier = identifier; this.data = save; this.info = info; this.position = position; }
public static WebMediaInfo GetMediaInfo(MediaSource source) { if (source.MediaType == WebStreamMediaType.TV) { // cache tv files for 10 seconds if (TvCache.ContainsKey(source.Id) && TvCache[source.Id].Item1.AddSeconds(10).CompareTo(DateTime.Now) > 0) { // cache is valid, use it return(TvCache[source.Id].Item2); } // get media info and save it to the cache TsBuffer buf = new TsBuffer(source.Id); WebMediaInfo info = GetMediaInfo(buf.GetCurrentFilePath(), true); TvCache[source.Id] = new Tuple <DateTime, WebMediaInfo>(DateTime.Now, info); return(info); } else if (!source.Exists) { throw new FileNotFoundException(); } else if (source.SupportsDirectAccess) { using (var impersonator = source.GetImpersonator()) { return(GetMediaInfo(source.GetPath(), false)); } } else { // not (yet?) supported throw new NotSupportedException(); } }
public void Save(MediaSource src, WebMediaInfo info) { lock (cache) { cache[src.GetUniqueIdentifier()] = info; } isDirty = true; }
private static string GetFullInfoString(WebMediaInfo info, long fileSize) { int index = 0; double realSize = fileSize; while (realSize > 1024) { index++; realSize /= 1024; } return(String.Format("{0}, {1:#.#} {2}", GetShortQualityName(info), realSize, units[index])); }
public static WebMediaInfo GetMediaInfo(MediaSource source) { // Timeshiftings are a special case, as they can't be cached and need an additional path resolving step if (source.MediaType == WebMediaType.TV) { if (tvCache.ContainsKey(source.Id) && DateTime.Now - tvCache[source.Id].Item1 > TimeSpan.FromSeconds(60)) { return(tvCache[source.Id].Item2); } TsBuffer tsBuffer = new TsBuffer(source.Id); Log.Debug("Using path {0} from TS buffer {1} as source for {2}", tsBuffer.GetCurrentFilePath(), source.Id, source.GetDebugName()); WebMediaInfo info = LoadMediaInfo(tsBuffer.GetCurrentFilePath()); tvCache[source.Id] = new Tuple <DateTime, WebMediaInfo>(DateTime.Now, info); return(info); } using (var context = source.CreateNetworkContext()) { // verify the file actually exists and is accessible over the local file system if (!source.Exists) { Log.Warn("Trying to load MediaInfo for {0}, which does not exist or is inaccessible", source.GetDebugName()); return(null); } else if (!source.SupportsDirectAccess) { Log.Warn("Loading MediaInfo for non-direct access source {0} isn't supported yet", source.GetDebugName()); return(null); } // if we got the file in the cache, return it if we have it and the file hasn't been changed var fileInfo = source.GetFileInfo(); if (source.MediaType != WebMediaType.TV && persistentCache.HasForSource(source)) { var cachedItem = persistentCache.GetForSource(source); if (cachedItem.Size == fileInfo.Size && cachedItem.CachedDate >= fileInfo.LastModifiedTime) { return(cachedItem.Info); } } var info = LoadMediaInfo(context.RewritePath(source.GetPath())); if (info != null) { persistentCache.Save(source, new CachedInfoWrapper(info, fileInfo)); } return(info); } }
public static WebMediaInfo GetMediaInfo(MediaSource source) { // we can't use our persistent cache for TV unfortunately, but we do cache them in memory for 60 seconds if (source.MediaType == WebMediaType.TV) { if (tvCache.ContainsKey(source.Id) && DateTime.Now - tvCache[source.Id].Item1 > TimeSpan.FromSeconds(60)) { return(tvCache[source.Id].Item2); } // save it to our memory cache for a while TsBuffer buf = new TsBuffer(source.Id); string path = buf.GetCurrentFilePath(); Log.Debug("Using path {0} from TS buffer {1} as source for {2}", path, source.Id, source.GetDebugName()); WebMediaInfo info = DoLoadMediaInfo(buf.GetCurrentFilePath(), true); tvCache[source.Id] = new Tuple <DateTime, WebMediaInfo>(DateTime.Now, info); return(info); } // load this item from persistent disk cache, if possible if (persistentCache.HasForSource(source)) { return(persistentCache.GetForSource(source)); } // some checks that only matter when we are actually going to load it from disk if (!source.Exists) { Log.Warn("Trying to load mediainfo for {0}, which doesn't seem to exist", source.GetDebugName()); return(null); } else if (!source.SupportsDirectAccess) { // not (yet?) supported Log.Warn("Loading mediainfo for non-direct access source {0} isn't supported yet", source.GetDebugName()); return(null); } // actually load it WebMediaInfo outInfo; using (var impersonator = source.GetImpersonator()) { outInfo = DoLoadMediaInfo(source.GetPath(), false); } if (outInfo != null) { persistentCache.Save(source, outInfo); } return(outInfo); }
public static string GetShortQualityName(WebMediaInfo info) { WebVideoStream vidStream = info.VideoStreams.First(); if (vidStream.Width >= 1920 || vidStream.Height >= 1080) { return("1080p"); } if (vidStream.Width >= 1280 || vidStream.Height >= 720) { return("720p"); } return("SD"); }
private void LoadMediaInfo(WebMediaInfo info) { if (info == null) { Log("No MediaInfo available"); return; } mInfo = info; Log(String.Format("MediaInfo: streams: {0} video, {1} audio, {2} subtitle", info.VideoStreams.Count, info.AudioStreams.Count, info.SubtitleStreams.Count)); if (info.VideoStreams.Count() > 0) { WebVideoStream vid = info.VideoStreams.First(); Log(String.Format("MediaInfo: video {0}x{1}; {2}; {3}", vid.Width, vid.Height, vid.DisplayAspectRatioString, vid.Codec)); } // audio cbLanguage.Items.Clear(); int i = 1; foreach (WebAudioStream audio in info.AudioStreams) { string name = "Audio stream #" + i++; if (!String.IsNullOrEmpty(audio.Language)) { name += ": " + audio.Language; } if (!String.IsNullOrEmpty(audio.Title)) { name += ": " + audio.Title; } cbLanguage.Items.Add(name); } // subtitle cbSubtitle.Items.Clear(); i = 1; foreach (WebSubtitleStream stream in info.SubtitleStreams) { string name = "Subtitle stream #" + i++ + " (" + stream.ID + ")"; if (!String.IsNullOrEmpty(stream.Language)) { name += ": " + stream.Language; } cbSubtitle.Items.Add(name); } }
public static decimal DEFAULT_ASPECT_RATIO = (decimal)16 / 9; // most new material is 16:9 these days public static WebMediaInfo LoadMediaInfoOrSurrogate(MediaSource source) { WebMediaInfo info; try { info = MediaInfoWrapper.GetMediaInfo(source); if (info != null) { return(info); } } catch (Exception ex) { Log.Warn(String.Format("Failed to load MediaInfo for {0}", source.GetDebugName()), ex); } WebMediaInfo surr = new WebMediaInfo(); surr.Duration = 0; surr.SubtitleStreams = new List <WebSubtitleStream>(); surr.AudioStreams = new List <WebAudioStream>() { new WebAudioStream() { Channels = 2, Codec = "Unknown", ID = 1, Index = 0, Language = "und", // yes, that's valid ISO 639 (I think) LanguageFull = "Unknown", } }; surr.VideoStreams = new List <WebVideoStream>() { new WebVideoStream() { Codec = "Unknown", DisplayAspectRatio = DEFAULT_ASPECT_RATIO, DisplayAspectRatioString = "16:9", ID = 2, Index = 0, Height = 720, Width = 1280 } }; return(surr); }
public static string GetShortQualityName(WebMediaInfo info) { if (!info.VideoStreams.Any()) { return(UIStrings.Unknown); } WebVideoStream vidStream = info.VideoStreams.First(); if (vidStream.Width >= 1920 || vidStream.Height >= 1080) { return(vidStream.Interlaced ? "1080i" : "1080p"); } if (vidStream.Width >= 1280 || vidStream.Height >= 720) { return(vidStream.Interlaced ? "720i" : "720p"); } return("SD"); }
public static WebMediaInfo LoadMediaInfoOrSurrogate(MediaSource source) { WebMediaInfo info = MediaInfoWrapper.GetMediaInfo(source); if (info != null) { return(info); } WebMediaInfo surr = new WebMediaInfo(); surr.Duration = 0; surr.SubtitleStreams = new List <WebSubtitleStream>(); surr.AudioStreams = new List <WebAudioStream>() { new WebAudioStream() { Channels = 2, Codec = "Unknown", ID = 1, Index = 0, Language = "und", // yes, that's valid ISO 639 (I think) LanguageFull = "Unknown", } }; surr.VideoStreams = new List <WebVideoStream>() { new WebVideoStream() { Codec = "Unknown", DisplayAspectRatio = 16 / 9, // this class is primarily used for TV data and that's mostly 16:9 these days afaik DisplayAspectRatioString = "16:9", ID = 2, Index = 0, Height = 1280, // gives this any problems? Width = 720 } }; return(surr); }
public CachedInfoWrapper(WebMediaInfo mediaInfo, WebFileInfo fileInfo) { CachedDate = DateTime.Now; Size = fileInfo.Size; Info = mediaInfo; }
public Resolution CalculateSize(TranscoderProfile profile, MediaSource source, WebMediaInfo info = null) { if (!profile.HasVideoStream) { return(new Resolution(0, 0)); } decimal aspect = (decimal)16 / 9; // the default aspect ratio if (source.MediaType != WebStreamMediaType.TV && profile != null) { if (info == null) { info = MediaInfoWrapper.GetMediaInfo(source); } if (info.VideoStreams.Count > 0) { aspect = info.VideoStreams.First().DisplayAspectRatio; } } return(Resolution.Calculate(aspect, profile.MaxOutputWidth, profile.MaxOutputHeight, 2)); }
public VLCWrapperParsingUnit(Reference <WebTranscodingInfo> save, WebMediaInfo info, int position) { data = save; this.info = info; this.position = position; }
private static WebMediaInfo DoLoadMediaInfo(string source, bool ignoreMemoryCache) { try { if (source == null || !File.Exists(source)) { Log.Warn("GetMediaInfo: File {0} doesn't exist or is not accessible", source); return(null); } // check cache if (!ignoreMemoryCache && memoryCache.ContainsKey(source)) { return(memoryCache[source]); } /* Loosely based upon MediaInfoWrapper.cs (mediaportal/Core/Player) from MediaPortal trunk r27491 as of 15 June 2011 * * Using the whole wrapper from MediaPortal is quite much porting work as it's cluttered with calls to other MP code. Referencing * MediaPortal.Core.dll also isn't an option as that pulls in a big tree of dependencies. * * TODO: Needs error handling * TODO: No support for DVDs yet * TODO: Aspect ratio doesn't work properly yet */ MediaInfo info = new MediaInfo(); info.Option("ParseSpeed", "0.3"); info.Open(source); WebMediaInfo retinfo = new WebMediaInfo(); retinfo.Container = info.Get(StreamKind.General, 0, "Format"); // video retinfo.VideoStreams = new List <WebVideoStream>(); int videoStreams = info.Count_Get(StreamKind.Video); for (int i = 0; i < videoStreams; i++) { retinfo.Duration = retinfo.Duration == 0 ? (long)StringToInt(info.Get(StreamKind.Video, i, "Duration")) : retinfo.Duration; string val = info.Get(StreamKind.Video, i, "DisplayAspectRatio"); retinfo.VideoStreams.Add(new WebVideoStream() { Codec = info.Get(StreamKind.Video, i, "Codec/String"), DisplayAspectRatio = StringToDecimal(info.Get(StreamKind.Video, i, "DisplayAspectRatio")), DisplayAspectRatioString = info.Get(StreamKind.Video, i, "DisplayAspectRatio/String"), Width = StringToInt(info.Get(StreamKind.Video, i, "Width")), Height = StringToInt(info.Get(StreamKind.Video, i, "Height")), ID = StringToInt(info.Get(StreamKind.Video, i, "ID")), Index = i }); } // audio codecs retinfo.AudioStreams = new List <WebAudioStream>(); int audioStreams = info.Count_Get(StreamKind.Audio); for (int i = 0; i < audioStreams; i++) { retinfo.Duration = retinfo.Duration == 0 ? (long)StringToInt(info.Get(StreamKind.Audio, i, "Duration")) : retinfo.Duration; retinfo.AudioStreams.Add(new WebAudioStream() { Channels = StringToInt(info.Get(StreamKind.Audio, i, "Channels")), Codec = info.Get(StreamKind.Audio, i, "Codec/String"), ID = StringToInt(info.Get(StreamKind.Audio, i, "ID")), Language = info.Get(StreamKind.Audio, i, "Language"), LanguageFull = info.Get(StreamKind.Audio, i, "Language/String"), Title = info.Get(StreamKind.Audio, i, "Title"), Index = i }); } // subtitle codecs retinfo.SubtitleStreams = new List <WebSubtitleStream>(); int subtitleStreams = info.Count_Get(StreamKind.Text); int scodecnr = 0; for (scodecnr = 0; scodecnr < subtitleStreams; scodecnr++) { retinfo.SubtitleStreams.Add(new WebSubtitleStream() { Language = info.Get(StreamKind.Text, scodecnr, "Language"), LanguageFull = info.Get(StreamKind.Text, scodecnr, "Language/String"), ID = StringToInt(info.Get(StreamKind.Text, scodecnr, "ID")), Index = scodecnr, Filename = null }); } // get max subtitle id var list = retinfo.SubtitleStreams.Select(x => x.ID); int lastId = list.Count() == 0 ? 0 : list.Max(); // standard name of external subtitle files string subfile = Path.Combine(Path.GetDirectoryName(source), Path.GetFileNameWithoutExtension(source) + ".srt"); if (File.Exists(subfile)) { retinfo.SubtitleStreams.Add(new WebSubtitleStream() { Language = "ext", LanguageFull = "External subtitle file", ID = ++lastId, // a file with so many streams seems quite unlikely to me Index = ++scodecnr, Filename = subfile }); } // language in subtitle filename var files = Directory.GetFiles(Path.GetDirectoryName(source), Path.GetFileNameWithoutExtension(source) + ".*.srt"); foreach (var file in files) { string basename = Path.GetFileName(file).Substring(Path.GetFileNameWithoutExtension(source).Length); string tag = basename.Substring(1, basename.Length - 5); retinfo.SubtitleStreams.Add(new WebSubtitleStream() { Language = LookupCountryCode(tag), LanguageFull = tag, ID = ++lastId, Index = ++scodecnr, Filename = file }); } // return info.Close(); if (!memoryCache.ContainsKey(source)) { memoryCache.Add(source, retinfo); } else { memoryCache[source] = retinfo; } return(retinfo); } catch (Exception ex) { Log.Error("Error parsing MediaInfo for " + source, ex); return(null); } }
public Resolution CalculateSize(TranscoderProfile profile, MediaSource source, WebMediaInfo info = null) { try { if (!profile.HasVideoStream) { return(new Resolution(0, 0)); } if (info == null) { info = MediaInfoHelper.LoadMediaInfoOrSurrogate(source); } if (info.VideoStreams.Count > 0) { var res = Resolution.Calculate(info.VideoStreams.First().DisplayAspectRatio, profile.MaxOutputWidth, profile.MaxOutputHeight, 2); if (res.Width == 0 && res.Height == 0) { return(new Resolution(info.VideoStreams.First().Width, info.VideoStreams.First().Height)); } return(res); } } catch (Exception ex) { Log.Warn("Failed to calculate size of output stream", ex); } // default return(Resolution.Calculate(MediaInfoHelper.DEFAULT_ASPECT_RATIO, profile.MaxOutputWidth, profile.MaxOutputHeight, 2)); }
public static string GetFullInfoString(WebMediaInfo info, WebFileInfo fileInfo) { return(GetFullInfoString(info, fileInfo.Size)); }
public static string GetFullInfoString(WebMediaInfo info, WebRecordingFileInfo fileInfo) { return(GetFullInfoString(fileInfo.Exists, info, fileInfo.Size)); }
public static string GetFullInfoString(bool accessible, WebMediaInfo info, WebRecordingFileInfo fileInfo) { return(GetFullInfoString(accessible, info, fileInfo.Size)); }
public static string GetShortQualityName(bool accessible, WebMediaInfo info) { return(accessible ? GetShortQualityName(info) : UIStrings.FileInaccessible); }
public static async Task <WebMediaInfo> ProcessAsync(IOwinContext context, string itemId, WebMediaType type) { if (itemId == null) { throw new BadRequestException("GetMediaInfo: itemId is null"); } Guid mediaItemId; MediaItem item; long duration = 0; string container = string.Empty; MetadataContainer info; List <WebVideoStream> webVideoStreams = new List <WebVideoStream>(); List <WebAudioStream> webAudioStreams = new List <WebAudioStream>(); List <WebSubtitleStream> webSubtitleStreams = new List <WebSubtitleStream>(); if (type == WebMediaType.TV || type == WebMediaType.Radio) { int channelIdInt; if (int.TryParse(itemId, out channelIdInt)) { item = new LiveTvMediaItem(Guid.Empty); info = MediaAnalyzer.ParseChannelStreamAsync(channelIdInt, (LiveTvMediaItem)item).Result; if (info == null) { throw new BadRequestException(String.Format("GetMediaInfo: Channel {0} stream not available", itemId)); } } else { throw new BadRequestException(String.Format("GetMediaInfo: Channel {0} not found", itemId)); } } else if (Guid.TryParse(itemId, out mediaItemId) == true) { ISet <Guid> necessaryMIATypes = new HashSet <Guid>(); necessaryMIATypes.Add(MediaAspect.ASPECT_ID); necessaryMIATypes.Add(ProviderResourceAspect.ASPECT_ID); necessaryMIATypes.Add(ImporterAspect.ASPECT_ID); ISet <Guid> optionalMIATypes = new HashSet <Guid>(); optionalMIATypes.Add(VideoAspect.ASPECT_ID); optionalMIATypes.Add(VideoStreamAspect.ASPECT_ID); optionalMIATypes.Add(VideoAudioStreamAspect.ASPECT_ID); optionalMIATypes.Add(AudioAspect.ASPECT_ID); optionalMIATypes.Add(ImageAspect.ASPECT_ID); item = MediaLibraryAccess.GetMediaItemById(context, itemId, necessaryMIATypes, optionalMIATypes); if (item == null) { throw new BadRequestException(String.Format("GetMediaInfo: No MediaItem found with id: {0}", itemId)); } } else { throw new BadRequestException(String.Format("GetMediaInfo: Media not found with id: {0}", itemId)); } // decide which type of media item we have info = await MediaAnalyzer.ParseMediaItemAsync(item); if (item.Aspects.ContainsKey(VideoAspect.ASPECT_ID)) { var videoAspect = item.GetAspect(VideoAspect.Metadata); var videoStreamAspect = item.GetAspect(VideoStreamAspect.Metadata); duration = Convert.ToInt64(videoStreamAspect.GetAttributeValue <long?>(VideoStreamAspect.ATTR_DURATION) ?? 0); bool interlaced = (videoStreamAspect.GetAttributeValue <string>(VideoStreamAspect.ATTR_VIDEO_TYPE) ?? "").ToLowerInvariant().Contains("interlaced"); foreach (var data in info.Metadata) { int edition = data.Key; int editionOffset = 0; if (edition >= 0) { editionOffset = (edition + 1) * ProfileMediaItem.EDITION_OFFSET; } if (info.IsVideo(edition)) { // Video WebVideoStream webVideoStream = new WebVideoStream(); webVideoStream.Codec = Convert.ToString(info.Video[edition].Codec); webVideoStream.DisplayAspectRatio = Convert.ToDecimal(info.Video[edition].AspectRatio ?? 0); webVideoStream.DisplayAspectRatioString = AspectRatioHelper.AspectRatioToString(Convert.ToDecimal(info.Video[edition].AspectRatio ?? 0)); webVideoStream.Height = Convert.ToInt32(info.Video[edition].Height ?? 0); webVideoStream.Width = Convert.ToInt32(info.Video[edition].Width ?? 0); webVideoStreams.Add(webVideoStream); webVideoStream.ID = info.Video[edition].StreamIndex + editionOffset; webVideoStream.Index = 0; webVideoStream.Interlaced = interlaced; container = info.Metadata[edition].VideoContainerType.ToString(); // Audio for (int i = 0; i < info.Audio[edition].Count; i++) { WebAudioStream webAudioStream = new WebAudioStream(); if (info.Audio[edition][i].Channels != null) { webAudioStream.Channels = info.Audio[edition][i].Channels.Value; } webAudioStream.Codec = info.Audio[edition][i].Codec.ToString(); webAudioStream.ID = info.Audio[edition][i].StreamIndex + editionOffset; webAudioStream.Index = i; if (info.Audio[edition][i].Language != null) { string language = info.Audio[edition][i].Language == string.Empty ? UNDEFINED : info.Audio[edition][i].Language; webAudioStream.Language = language; if (language != UNDEFINED) { webAudioStream.LanguageFull = new CultureInfo(language).EnglishName; if (item.HasEditions && item.Editions.Any(e => e.Value.SetNo == edition)) { webAudioStream.Title = item.Editions.First(e => e.Key == edition).Value.Name; } else if (item.GetPlayData(out var mime, out var mediaName)) { webAudioStream.Title = mediaName; } else { webAudioStream.Title = "?"; } if (string.IsNullOrEmpty(webAudioStream.Codec) == false) { webAudioStream.Title += webAudioStream.Title?.Length > 0 ? $" ({webAudioStream.Codec.ToUpperInvariant()})" : webAudioStream.Codec.ToUpperInvariant(); } } } webAudioStreams.Add(webAudioStream); } // Subtitles if (info.Subtitles[edition].Any()) { int firstMediaIdx = info.Subtitles[edition].Keys.First(); for (int i = 0; i < info.Subtitles[edition][firstMediaIdx].Count; i++) { WebSubtitleStream webSubtitleStream = new WebSubtitleStream(); webSubtitleStream.Filename = info.Subtitles[edition][firstMediaIdx][i].IsEmbedded ? "Embedded" : info.Subtitles[edition][firstMediaIdx][i].SourcePath; webSubtitleStream.ID = info.Subtitles[edition][firstMediaIdx][i].StreamIndex + editionOffset; webSubtitleStream.Index = i; if (info.Subtitles[edition][firstMediaIdx][i].Language != null) { string language = info.Subtitles[edition][firstMediaIdx][i].Language == string.Empty ? UNDEFINED : info.Subtitles[edition][firstMediaIdx][i].Language; webSubtitleStream.Language = language; webSubtitleStream.LanguageFull = language; if (language != UNDEFINED) { webSubtitleStream.LanguageFull = new CultureInfo(language).EnglishName; } } webSubtitleStreams.Add(webSubtitleStream); } } } } } else if (item.Aspects.ContainsKey(AudioAspect.ASPECT_ID)) { int edition = info.Metadata.Min(d => d.Key); if (info.IsAudio(edition)) { var audioAspect = item.GetAspect(AudioAspect.Metadata); duration = (long)audioAspect[AudioAspect.ATTR_DURATION]; container = info.Metadata[edition].AudioContainerType.ToString(); } } else if (item.Aspects.ContainsKey(ImageAspect.ASPECT_ID)) { int edition = info.Metadata.Min(d => d.Key); if (info.IsImage(edition)) { container = info.Metadata[edition].ImageContainerType.ToString(); } } WebMediaInfo webMediaInfo = new WebMediaInfo { Duration = duration * 1000, Container = container, VideoStreams = webVideoStreams, AudioStreams = webAudioStreams, SubtitleStreams = webSubtitleStreams }; return(webMediaInfo); }