public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { try { if (!(mediaItemAccessor is IFileSystemResourceAccessor)) return false; using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor)) { ILocalFsResourceAccessor lfsra = rah.LocalFsResourceAccessor; if (!lfsra.IsFile && lfsra.ResourceExists("BDMV")) { IFileSystemResourceAccessor fsraBDMV = lfsra.GetResource("BDMV"); if (fsraBDMV != null && fsraBDMV.ResourceExists("index.bdmv")) { // This line is important to keep in, if no VideoAspect is created here, the MediaItems is not detected as Video! MediaItemAspect.GetOrCreateAspect(extractedAspectData, VideoAspect.Metadata); MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata); mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, "video/bluray"); // BluRay disc using (lfsra.EnsureLocalFileSystemAccess()) { BDInfoExt bdinfo = new BDInfoExt(lfsra.LocalFileSystemPath); string title = bdinfo.GetTitle(); mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, title ?? mediaItemAccessor.ResourceName); // Check for BD disc thumbs FileInfo thumbnail = bdinfo.GetBiggestThumb(); if (thumbnail != null) { try { using (FileStream fileStream = new FileStream(thumbnail.FullName, FileMode.Open, FileAccess.Read)) using (MemoryStream resized = (MemoryStream)ImageUtilities.ResizeImage(fileStream, ImageFormat.Jpeg, MAX_COVER_WIDTH, MAX_COVER_HEIGHT)) { MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, resized.ToArray()); } } // Decoding of invalid image data can fail, but main MediaItem is correct. catch { } } } return true; } } } return false; } catch { // Only log at the info level here - And simply return false. This makes the importer know that we // couldn't perform our task here if (mediaItemAccessor != null) ServiceRegistration.Get<ILogger>().Info("BluRayMetadataExtractor: Exception reading source '{0}'", mediaItemAccessor.ResourcePathName); return false; } }
public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { try { if (forceQuickMode) return false; if (!(mediaItemAccessor is IFileSystemResourceAccessor)) return false; using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor)) return ExtractThumbnail(rah.LocalFsResourceAccessor, extractedAspectData); } catch (Exception e) { // Only log at the info level here - And simply return false. This lets the caller know that we // couldn't perform our task here. ServiceRegistration.Get<ILogger>().Error("VideoThumbnailer: Exception reading resource '{0}' (Text: '{1}')", e, mediaItemAccessor.CanonicalLocalResourcePath, e.Message); } return false; }
/// <summary> /// Adds the TsReader filter to the graph. /// </summary> protected override void AddSourceFilter() { // Render the file _sourceFilter = FilterLoader.LoadFilterFromDll("TsReader.ax", typeof(TsReader).GUID, true); IFileSourceFilter fileSourceFilter = (IFileSourceFilter)_sourceFilter; ITsReader tsReader = (ITsReader) _sourceFilter; tsReader.SetRelaxedMode(1); tsReader.SetTsReaderCallback(this); tsReader.SetRequestAudioChangeCallback(this); _graphBuilder.AddFilter(_sourceFilter, TSREADER_FILTER_NAME); _subtitleRenderer = new SubtitleRenderer(OnTextureInvalidated); _subtitleFilter = _subtitleRenderer.AddSubtitleFilter(_graphBuilder); if (_subtitleFilter != null) { _subtitleRenderer.RenderSubtitles = true; _subtitleRenderer.SetPlayer(this); } if (_resourceLocator.NativeResourcePath.IsNetworkResource) { //_resourceAccessor points to an rtsp:// stream var networkResourceAccessor = _resourceAccessor as INetworkResourceAccessor; if (networkResourceAccessor == null) throw new IllegalCallException("The TsVideoPlayer can only play network resources of type INetworkResourceAccessor"); ServiceRegistration.Get<ILogger>().Debug("{0}: Initializing for stream '{1}'", PlayerTitle, networkResourceAccessor.URL); fileSourceFilter.Load(networkResourceAccessor.URL, null); } else { // _resourceAccessor points to a local or remote mapped .ts file _localFsRaHelper = new LocalFsResourceAccessorHelper(_resourceAccessor); var localFileSystemResourceAccessor = _localFsRaHelper.LocalFsResourceAccessor; if (localFileSystemResourceAccessor == null) throw new IllegalCallException("The TsVideoPlayer can only play file resources of type ILocalFsResourceAccessor"); ServiceRegistration.Get<ILogger>().Debug("{0}: Initializing for stream '{1}'", PlayerTitle, localFileSystemResourceAccessor.LocalFileSystemPath); fileSourceFilter.Load(localFileSystemResourceAccessor.LocalFileSystemPath, null); } // Init GraphRebuilder _graphRebuilder = new GraphRebuilder(_graphBuilder, _sourceFilter, OnAfterGraphRebuild) { PlayerName = PlayerTitle }; }
public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { string fileName = mediaItemAccessor.ResourceName; if (!HasImageExtension(fileName)) return false; MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata); MediaItemAspect imageAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ImageAspect.Metadata); try { if (!(mediaItemAccessor is IFileSystemResourceAccessor)) return false; IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor; // Open a stream for media item to detect mimeType. using (Stream mediaStream = fsra.OpenRead()) { string mimeType = MimeTypeDetector.GetMimeType(mediaStream) ?? DEFAULT_MIMETYPE; mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, mimeType); mediaAspect.SetAttribute(MediaAspect.ATTR_SIZE, fsra.Size); } // Extract EXIF information from media item. using (ExifMetaInfo.ExifMetaInfo exif = new ExifMetaInfo.ExifMetaInfo(fsra)) { mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, ProviderPathHelper.GetFileNameWithoutExtension(fileName)); mediaAspect.SetAttribute(MediaAspect.ATTR_RECORDINGTIME, exif.OriginalDate != DateTime.MinValue ? exif.OriginalDate : fsra.LastChanged); mediaAspect.SetAttribute(MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(exif.ImageDescription)); if (exif.PixXDim.HasValue) imageAspect.SetAttribute(ImageAspect.ATTR_WIDTH, (int) exif.PixXDim); if (exif.PixYDim.HasValue) imageAspect.SetAttribute(ImageAspect.ATTR_HEIGHT, (int) exif.PixYDim); imageAspect.SetAttribute(ImageAspect.ATTR_MAKE, StringUtils.TrimToNull(exif.EquipMake)); imageAspect.SetAttribute(ImageAspect.ATTR_MODEL, StringUtils.TrimToNull(exif.EquipModel)); if (exif.ExposureBias.HasValue) imageAspect.SetAttribute(ImageAspect.ATTR_EXPOSURE_BIAS, ((double) exif.ExposureBias).ToString()); imageAspect.SetAttribute(ImageAspect.ATTR_EXPOSURE_TIME, exif.ExposureTime); imageAspect.SetAttribute(ImageAspect.ATTR_FLASH_MODE, StringUtils.TrimToNull(exif.FlashMode)); if (exif.FNumber.HasValue) imageAspect.SetAttribute(ImageAspect.ATTR_FNUMBER, string.Format("F {0}", (double) exif.FNumber)); imageAspect.SetAttribute(ImageAspect.ATTR_ISO_SPEED, StringUtils.TrimToNull(exif.ISOSpeed)); imageAspect.SetAttribute(ImageAspect.ATTR_ORIENTATION, (Int32) (exif.OrientationType ?? 0)); imageAspect.SetAttribute(ImageAspect.ATTR_METERING_MODE, exif.MeteringMode.ToString()); if (exif.Latitude.HasValue && exif.Longitude.HasValue) { imageAspect.SetAttribute(ImageAspect.ATTR_LATITUDE, exif.Latitude); imageAspect.SetAttribute(ImageAspect.ATTR_LONGITUDE, exif.Longitude); CivicAddress locationInfo; if (!forceQuickMode && GeoLocationService.Instance.TryLookup(new GeoCoordinate(exif.Latitude.Value, exif.Longitude.Value), out locationInfo)) { imageAspect.SetAttribute(ImageAspect.ATTR_CITY, locationInfo.City); imageAspect.SetAttribute(ImageAspect.ATTR_STATE, locationInfo.StateProvince); imageAspect.SetAttribute(ImageAspect.ATTR_COUNTRY, locationInfo.CountryRegion); } } using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor)) using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess()) { string localFsResourcePath = rah.LocalFsResourceAccessor.LocalFileSystemPath; if (localFsResourcePath != null) { // In quick mode only allow thumbs taken from cache. bool cachedOnly = forceQuickMode; // Thumbnail extraction IThumbnailGenerator generator = ServiceRegistration.Get<IThumbnailGenerator>(); byte[] thumbData; ImageType imageType; if (generator.GetThumbnail(localFsResourcePath, cachedOnly, out thumbData, out imageType)) MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData); } } } return true; } catch (Exception e) { // Only log at the info level here - And simply return false. This makes the importer know that we // couldn't perform our task here. ServiceRegistration.Get<ILogger>().Info("ImageMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message); } return false; }
/// <summary> /// Tries to load chapter information from external file. This method checks for ComSkip files (.txt). /// </summary> /// <returns></returns> protected virtual bool EnumerateExternalChapters() { var fsra = _resourceAccessor as IFileSystemResourceAccessor; if (fsra == null || !fsra.IsFile) return false; try { string filePath = _resourceAccessor.CanonicalLocalResourcePath.ToString(); string metaFilePath = ProviderPathHelper.ChangeExtension(filePath, ".txt"); IResourceAccessor raTextFile; if (!ResourcePath.Deserialize(metaFilePath).TryCreateLocalResourceAccessor(out raTextFile)) return false; List<double> positions = new List<double>(); using (LocalFsResourceAccessorHelper lfsra = new LocalFsResourceAccessorHelper(raTextFile)) { if (lfsra.LocalFsResourceAccessor == null) return false; using (var stream = lfsra.LocalFsResourceAccessor.OpenRead()) using (var chaptersReader = new StreamReader(stream)) { string line = chaptersReader.ReadLine(); int fps; if (string.IsNullOrWhiteSpace(line) || !int.TryParse(line.Substring(line.LastIndexOf(' ') + 1), out fps)) { ServiceRegistration.Get<ILogger>().Warn("VideoPlayer: EnumerateExternalChapters() - Invalid ComSkip chapter file"); return false; } double framesPerSecond = fps / 100.0; while ((line = chaptersReader.ReadLine()) != null) { if (String.IsNullOrEmpty(line)) continue; string[] tokens = line.Split('\t'); if (tokens.Length != 2) continue; foreach (var token in tokens) { int time; if (int.TryParse(token, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out time)) positions.Add(time / framesPerSecond); } } } } // Insert start of video as position if (!positions.Contains(0d)) positions.Insert(0, 0d); var chapterNames = new List<string>(); var chapterTimes = new List<double>(); for (int index = 0; index < positions.Count - 1; index++) { var timeFrom = positions[index]; var timeTo = positions[index + 1]; // Filter out segments with less than 2 seconds duration if (timeTo - timeFrom <= 2) continue; var chapterName = string.Format("ComSkip {0} [{1} - {2}]", chapterNames.Count + 1, FormatDuration(timeFrom), FormatDuration(timeTo)); chapterNames.Add(chapterName); chapterTimes.Add(timeFrom); } _chapterNames = chapterNames.ToArray(); _chapterTimestamps = chapterTimes.ToArray(); return _chapterNames.Length > 0; } catch (Exception ex) { ServiceRegistration.Get<ILogger>().Error("VideoPlayer: EnumerateExternalChapters() - Exception while reading ComSkip chapter file", ex); return false; } }
public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { try { VideoResult result = null; IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor; if (fsra == null) return false; if (!fsra.IsFile && fsra.ResourceExists("VIDEO_TS")) { IFileSystemResourceAccessor fsraVideoTs = fsra.GetResource("VIDEO_TS"); if (fsraVideoTs != null && fsraVideoTs.ResourceExists("VIDEO_TS.IFO")) { // Video DVD using (MediaInfoWrapper videoTsInfo = ReadMediaInfo(fsraVideoTs.GetResource("VIDEO_TS.IFO"))) { if (!videoTsInfo.IsValid || videoTsInfo.GetVideoCount() == 0) return false; // Invalid video_ts.ifo file result = VideoResult.CreateDVDInfo(fsra.ResourceName, videoTsInfo); } // Iterate over all video files; MediaInfo finds different audio/video metadata for each .ifo file ICollection<IFileSystemResourceAccessor> files = fsraVideoTs.GetFiles(); if (files != null) foreach (IFileSystemResourceAccessor file in files) { string lowerPath = (file.ResourcePathName ?? string.Empty).ToLowerInvariant(); if (!lowerPath.EndsWith(".ifo") || lowerPath.EndsWith("video_ts.ifo")) continue; using (MediaInfoWrapper mediaInfo = ReadMediaInfo(file)) { // Before we start evaluating the file, check if it is a video at all if (mediaInfo.IsValid && mediaInfo.GetVideoCount() == 0) continue; result.AddMediaInfo(mediaInfo); } } } } else if (fsra.IsFile) { string filePath = fsra.ResourcePathName; if (!HasVideoExtension(filePath)) return false; using (MediaInfoWrapper fileInfo = ReadMediaInfo(fsra)) { // Before we start evaluating the file, check if it is a video at all if (!fileInfo.IsValid || (fileInfo.GetVideoCount() == 0 && !IsWorkaroundRequired(filePath))) return false; string mediaTitle = DosPathHelper.GetFileNameWithoutExtension(fsra.ResourceName); result = VideoResult.CreateFileInfo(mediaTitle, fileInfo); } using (Stream stream = fsra.OpenRead()) result.MimeType = MimeTypeDetector.GetMimeType(stream, DEFAULT_MIMETYPE); } if (result != null) { result.UpdateMetadata(extractedAspectData); using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor)) { ILocalFsResourceAccessor lfsra = rah.LocalFsResourceAccessor; if (lfsra != null) { MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_SIZE, lfsra.Size); MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, lfsra.LastChanged); ExtractMatroskaTags(lfsra, extractedAspectData, forceQuickMode); ExtractMp4Tags(lfsra, extractedAspectData, forceQuickMode); ExtractThumbnailData(lfsra, extractedAspectData, forceQuickMode); } return true; } } } catch (Exception e) { // Only log at the info level here - And simply return false. This lets the caller know that we // couldn't perform our task here. ServiceRegistration.Get<ILogger>().Info("VideoMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message); } return false; }
public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { try { if (!(mediaItemAccessor is IFileSystemResourceAccessor)) return false; using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor)) { ILocalFsResourceAccessor lfsra = rah.LocalFsResourceAccessor; if (!lfsra.IsFile && lfsra.ResourceExists("BDMV")) { IFileSystemResourceAccessor fsraBDMV = lfsra.GetResource("BDMV"); if (fsraBDMV != null && fsraBDMV.ResourceExists("index.bdmv")) { // This line is important to keep in, if no VideoAspect is created here, the MediaItems is not detected as Video! MediaItemAspect.GetOrCreateAspect(extractedAspectData, VideoAspect.Metadata); MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata); mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, "video/bluray"); // BluRay disc string bdmvDirectory = lfsra.LocalFileSystemPath; BDInfoExt bdinfo = new BDInfoExt(bdmvDirectory); string title = bdinfo.GetTitle(); mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, title ?? mediaItemAccessor.ResourceName); // Check for BD disc thumbs FileInfo thumbnail = bdinfo.GetBiggestThumb(); if (thumbnail != null) { byte[] binary = new byte[thumbnail.Length]; using (FileStream fileStream = new FileStream(thumbnail.FullName, FileMode.Open, FileAccess.Read)) using (BinaryReader binaryReader = new BinaryReader(fileStream)) binaryReader.Read(binary, 0, binary.Length); MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, binary); } return true; } } } return false; } catch { // Only log at the info level here - And simply return false. This makes the importer know that we // couldn't perform our task here if (mediaItemAccessor != null) ServiceRegistration.Get<ILogger>().Info("BluRayMetadataExtractor: Exception reading source '{0}'", mediaItemAccessor.ResourcePathName); return false; } }
/// <summary> /// Adds the TsReader filter to the graph. /// </summary> protected override void AddSourceFilter() { // Render the file _sourceFilter = FilterLoader.LoadFilterFromDll("TsReader.ax", typeof(TsReader).GUID, true); IFileSourceFilter fileSourceFilter = (IFileSourceFilter)_sourceFilter; ITsReader tsReader = (ITsReader)_sourceFilter; tsReader.SetRelaxedMode(1); tsReader.SetTsReaderCallback(this); tsReader.SetRequestAudioChangeCallback(this); _graphBuilder.AddFilter(_sourceFilter, TSREADER_FILTER_NAME); _subtitleRenderer = new SubtitleRenderer(OnTextureInvalidated); _subtitleFilter = _subtitleRenderer.AddSubtitleFilter(_graphBuilder); if (_subtitleFilter != null) { _subtitleRenderer.RenderSubtitles = true; _subtitleRenderer.SetPlayer(this); } // For supporting CC AddClosedCaptionsFilter(); if (_resourceLocator.NativeResourcePath.IsNetworkResource) { // _resourceAccessor points to an rtsp:// stream or network file var sourcePathOrUrl = SourcePathOrUrl; if (sourcePathOrUrl == null) throw new IllegalCallException("The TsVideoPlayer can only play network resources of type INetworkResourceAccessor"); ServiceRegistration.Get<ILogger>().Debug("{0}: Initializing for stream '{1}'", PlayerTitle, sourcePathOrUrl); IDisposable accessEnsurer = null; if (IsLocalFilesystemResource) accessEnsurer = ((ILocalFsResourceAccessor)_resourceAccessor).EnsureLocalFileSystemAccess(); using (accessEnsurer) { int hr = fileSourceFilter.Load(SourcePathOrUrl, null); new HRESULT(hr).Throw(); } } else { // _resourceAccessor points to a local or remote mapped .ts file _localFsRaHelper = new LocalFsResourceAccessorHelper(_resourceAccessor); var localFileSystemResourceAccessor = _localFsRaHelper.LocalFsResourceAccessor; if (localFileSystemResourceAccessor == null) throw new IllegalCallException("The TsVideoPlayer can only play file resources of type ILocalFsResourceAccessor"); using (localFileSystemResourceAccessor.EnsureLocalFileSystemAccess()) { ServiceRegistration.Get<ILogger>().Debug("{0}: Initializing for stream '{1}'", PlayerTitle, localFileSystemResourceAccessor.LocalFileSystemPath); int hr = fileSourceFilter.Load(localFileSystemResourceAccessor.LocalFileSystemPath, null); new HRESULT(hr).Throw(); } } // Init GraphRebuilder _graphRebuilder = new GraphRebuilder(_graphBuilder, _sourceFilter, OnAfterGraphRebuild) { PlayerName = PlayerTitle }; }