コード例 #1
0
        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))
                {
                    string localFsPath = rah.LocalFsResourceAccessor.LocalFileSystemPath;
                    return(ExtractSeriesData(localFsPath, 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>().Info("SeriesMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
コード例 #2
0
        private void ExtractLocalImages(IDictionary <Guid, IList <MediaItemAspect> > aspects, Guid?albumMediaItemId, IDictionary <Guid, string> artistMediaItems, string albumTitle)
        {
            if (BaseInfo.IsVirtualResource(aspects))
            {
                return;
            }

            IResourceLocator mediaItemLocater = GetResourceLocator(aspects);

            if (mediaItemLocater == null)
            {
                return;
            }

            ExtractFolderImages(mediaItemLocater, albumMediaItemId, artistMediaItems, albumTitle);
            using (IResourceAccessor mediaItemAccessor = mediaItemLocater.CreateAccessor())
            {
                using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                {
                    using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                    {
                        ExtractFileImages(rah.LocalFsResourceAccessor, albumMediaItemId, albumTitle);
                    }
                }
            }
        }
コード例 #3
0
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool importOnly, bool forceQuickMode)
        {
            try
            {
                if (forceQuickMode)
                {
                    return(false);
                }
                if (importOnly)
                {
                    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);
        }
コード例 #4
0
        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)
                            {
                                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);
            }
        }
コード例 #5
0
        private void ExtractLocalImages(IDictionary <Guid, IList <MediaItemAspect> > aspects, Guid?episodeMediaItemId, Guid?seriesMediaItemId, Guid?seasonMediaItemId, EpisodeInfo episode, SeriesInfo series, SeasonInfo season, IDictionary <Guid, string> actorMediaItems)
        {
            if (BaseInfo.IsVirtualResource(aspects))
            {
                return;
            }

            IResourceLocator mediaItemLocater = GetResourceLocator(aspects);

            if (mediaItemLocater == null)
            {
                return;
            }

            ExtractFolderImages(mediaItemLocater, episodeMediaItemId, seriesMediaItemId, seasonMediaItemId, episode, series, season, actorMediaItems);
            using (IResourceAccessor mediaItemAccessor = mediaItemLocater.CreateAccessor())
            {
                using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                {
                    using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                    {
                        ExtractMkvImages(rah.LocalFsResourceAccessor, seriesMediaItemId, series);
                    }
                }
            }
        }
コード例 #6
0
        /// <summary>
        /// Reads all tag images and caches them in the <see cref="IFanArtCache"/> service.
        /// </summary>
        /// <param name="mediaItemLocator"><see cref="IResourceLocator>"/> that points to the file.</param>
        /// <param name="mediaItemId">Id of the media item.</param>
        /// <param name="title">Title of the media item.</param>
        /// <returns><see cref="Task"/> that completes when the images have been cached.</returns>
        protected async Task ExtractFanArt(IResourceLocator mediaItemLocator, Guid mediaItemId, string title, IDictionary <Guid, IList <MediaItemAspect> > aspects)
        {
            try
            {
                //File based access
                using (IResourceAccessor mediaItemAccessor = mediaItemLocator.CreateAccessor())
                    using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                        using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                        {
                            if (MKV_EXTENSIONS.Contains(ResourcePathHelper.GetExtension(mediaItemLocator.NativeResourcePath.FileName)))
                            {
                                await ExtractMkvFanArt(rah.LocalFsResourceAccessor, mediaItemId, title).ConfigureAwait(false);
                            }
                            if (MP4_EXTENSIONS.Contains(ResourcePathHelper.GetExtension(mediaItemLocator.NativeResourcePath.FileName)))
                            {
                                await ExtractTagFanArt(rah.LocalFsResourceAccessor, mediaItemId, title).ConfigureAwait(false);
                            }

                            //Don't create thumbs if they already exist or if it is a movie (they use posters)
                            var thumbs = ServiceRegistration.Get <IFanArtCache>().GetFanArtFiles(mediaItemId, FanArtTypes.Thumbnail);
                            if (!thumbs.Any() && !aspects.ContainsKey(ThumbnailLargeAspect.ASPECT_ID) && !aspects.ContainsKey(MovieAspect.ASPECT_ID))
                            {
                                await ExtractThumbnailFanArt(rah.LocalFsResourceAccessor, mediaItemId, title, aspects);
                            }
                        }
            }
            catch (Exception ex)
            {
                Logger.Warn("VideoFanArtHandler: Exception while reading MKV tag images for '{0}'", ex, mediaItemLocator.NativeResourcePath);
            }
        }
コード例 #7
0
        public async Task <bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool forceQuickMode)
        {
            try
            {
                if (forceQuickMode)
                {
                    return(false);
                }

                byte[] thumb;
                // We only want to create missing thumbnails here, so check for existing ones first
                if (MediaItemAspect.TryGetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, out thumb) && thumb != null)
                {
                    return(false);
                }

                if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                {
                    return(false);
                }
                using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                    return(await ExtractThumbnailAsync(rah.LocalFsResourceAccessor, extractedAspectData).ConfigureAwait(false));
            }
            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("OCVVideoThumbnailer: Exception reading resource '{0}' (Text: '{1}')", e, mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
コード例 #8
0
        private void ExtractLocalImages(IDictionary <Guid, IList <MediaItemAspect> > aspects, Guid?movieMediaItemId, Guid?collectionMediaItemId, string movieName, string collectionName, IDictionary <Guid, string> actorMediaItems)
        {
            if (BaseInfo.IsVirtualResource(aspects))
            {
                return;
            }

            IResourceLocator mediaItemLocater = GetResourceLocator(aspects);

            if (mediaItemLocater == null)
            {
                return;
            }

            ExtractFolderImages(mediaItemLocater, movieMediaItemId, collectionMediaItemId, movieName, collectionName, actorMediaItems);
            using (IResourceAccessor mediaItemAccessor = mediaItemLocater.CreateAccessor())
            {
                using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                {
                    using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                    {
                        ExtractMkvImages(rah.LocalFsResourceAccessor, movieMediaItemId, movieName);
                    }
                }
            }
        }
コード例 #9
0
        /// <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 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);

                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");
                }

                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
            };
        }
コード例 #10
0
        protected override async Task <List <SubtitleInfo> > SearchSeriesEpisodeSubtitlesAsync(SubtitleInfo subtitleSearch, List <string> languages)
        {
            List <SubDbSearchResult> results = new List <SubDbSearchResult>();
            var mediaFile = subtitleSearch.MediaFiles.First();

            using (IResourceAccessor mediaItemAccessor = mediaFile.CreateAccessor())
                using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                    using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                    {
                        using (var stream = await rah.LocalFsResourceAccessor.OpenReadAsync())
                        {
                            if (stream != null)
                            {
                                results = await _subDbHandler.SearchSubtitlesAsync(stream);
                            }
                        }
                    }

            if (!results.Any())
            {
                return(new List <SubtitleInfo>());
            }

            var langs = languages.Select(s => new CultureInfo(s).TwoLetterISOLanguageName);

            if (!results.Any(r => langs.Any(l => l.Equals(r.LanguageCode, System.StringComparison.InvariantCultureIgnoreCase))))
            {
                return(new List <SubtitleInfo>());
            }

            return(results.Where(r => langs.Any(l => l.Equals(r.LanguageCode, System.StringComparison.InvariantCultureIgnoreCase))).
                   Select(s => new SubtitleInfo
            {
                DisplayName = Path.GetFileNameWithoutExtension(mediaFile.NativeResourcePath.FileName),
                Name = Path.GetFileNameWithoutExtension(mediaFile.NativeResourcePath.FileName) + ".srt",
                TvdbId = subtitleSearch.TvdbId,
                Language = new CultureInfo(s.LanguageCode).Name,
                MediaFiles = subtitleSearch.MediaFiles,
                MediaTitle = subtitleSearch.MediaTitle,
                Episode = subtitleSearch.Episode,
                Season = subtitleSearch.Season,
                SubtitleId = s.DownloadUrl,
                Year = subtitleSearch.Year,
                DataProviders = new List <string>()
                {
                    _name
                }
            }).ToList());
        }
コード例 #11
0
 /// <summary>
 /// Reads all tag images and caches them in the <see cref="IFanArtCache"/> service.
 /// </summary>
 /// <param name="mediaItemLocator"><see cref="IResourceLocator>"/> that points to the file.</param>
 /// <param name="mediaItemId">Id of the media item.</param>
 /// <param name="title">Title of the media item.</param>
 /// <returns><see cref="Task"/> that completes when the images have been cached.</returns>
 protected async Task ExtractTagFanArt(IResourceLocator mediaItemLocator, Guid mediaItemId, string title)
 {
     try
     {
         //File based access
         using (IResourceAccessor mediaItemAccessor = mediaItemLocator.CreateAccessor())
             using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                 using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                     await ExtractTagFanArt(rah.LocalFsResourceAccessor, mediaItemId, title).ConfigureAwait(false);
     }
     catch (Exception ex)
     {
         Logger.Warn("AudioFanArtHandler: Exception while reading MKV tag images for '{0}'", ex, mediaItemLocator.NativeResourcePath);
     }
 }
コード例 #12
0
        public async Task <bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool forceQuickMode)
        {
            IResourceAccessor disposeAccessor = null;

            try
            {
                IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;

                if (fsra == null)
                {
                    return(false);
                }

                if (!fsra.IsFile)
                {
                    if (!IsChainedResourceProvider(mediaItemAccessor))
                    {
                        return(false);
                    }
                    // The importer mounts iso and zip files as virtual directories but we need the accessor
                    // to the original file so we have to create one here and remember to dispose it later.
                    ResourcePath path = new ResourcePath(new[] { mediaItemAccessor.CanonicalLocalResourcePath.BasePathSegment });
                    if (!path.TryCreateLocalResourceAccessor(out disposeAccessor))
                    {
                        return(false);
                    }
                }

                using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(disposeAccessor ?? mediaItemAccessor))
                    return(await ExtractGameData(rah.LocalFsResourceAccessor, extractedAspectData, forceQuickMode).ConfigureAwait(false));
            }
            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.
                Logger.Info("GamesMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            finally
            {
                if (disposeAccessor != null)
                {
                    disposeAccessor.Dispose();
                }
            }
            return(false);
        }
コード例 #13
0
        protected virtual async Task <bool> SaveSubtitleAsync(SubtitleInfo subtitle, IDictionary <BaseSubtitleMatch <TId>, byte[]> downloads, bool overwriteExisting)
        {
            var mediaFile         = subtitle.MediaFiles.First();
            var namingTemplate    = ResourcePath.GetFileNameWithoutExtension(mediaFile.NativeResourcePath.FileName);
            var templatePartMatch = _regexMultiPartVideo.Match(namingTemplate);

            foreach (var subtitleMatch in downloads.Keys)
            {
                var    subPartMatch = _regexMultiPartVideo.Match(subtitleMatch.ItemName);
                string subName      = namingTemplate;
                if (subPartMatch.Success && templatePartMatch.Success)
                {
                    if (!int.TryParse(templatePartMatch.Groups["disc"].Value, out var _) || !int.TryParse(subPartMatch.Groups["disc"].Value, out var partNum))
                    {
                        continue;
                    }

                    subName = _regexMultiPartVideo.Replace(namingTemplate, "${1}${2}${4}" + partNum + "${3}");
                }

                string       lang         = new CultureInfo(subtitleMatch.Language).EnglishName;
                var          dir          = ResourcePathHelper.GetDirectoryName(mediaFile.NativeResourcePath.Serialize());
                var          sub          = $"{subName}.{lang}{Path.GetExtension(subtitleMatch.ItemName)}";
                ResourcePath subtitlePath = ResourcePath.Deserialize(dir);

                //File based access
                var resLoc = new ResourceLocator(mediaFile.NativeSystemId, subtitlePath);
                using (IResourceAccessor mediaItemAccessor = resLoc.CreateAccessor())
                    using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                        using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                        {
                            using (var stream = rah.LocalFsResourceAccessor.CreateOpenWrite(sub, overwriteExisting))
                            {
                                var bytes = downloads[subtitleMatch];
                                if (stream != null)
                                {
                                    await stream.WriteAsync(bytes, 0, bytes.Length);
                                }
                            }
                        }
            }
            return(true);
        }
コード例 #14
0
        public Task <bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool forceQuickMode)
        {
            try
            {
                IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;
                if (fsra == null || !fsra.IsFile)
                {
                    return(Task.FromResult(false));
                }

                using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                    return(Task.FromResult(ExtractGoodMergeData(rah.LocalFsResourceAccessor.LocalFileSystemPath, 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.
                Logger.Info("GoodMergeMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(Task.FromResult(false));
        }
コード例 #15
0
 /// <summary>
 /// Reads all tag images and caches them in the <see cref="IFanArtCache"/> service.
 /// </summary>
 /// <param name="mediaItemLocator"><see cref="IResourceLocator>"/> that points to the file.</param>
 /// <param name="mediaItemId">Id of the media item.</param>
 /// <param name="title">Title of the media item.</param>
 /// <returns><see cref="Task"/> that completes when the images have been cached.</returns>
 protected async Task ExtractFanArt(IResourceLocator mediaItemLocator, Guid mediaItemId, string title)
 {
     try
     {
         //File based access
         using (IResourceAccessor mediaItemAccessor = mediaItemLocator.CreateAccessor())
             using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                 using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                 {
                     if (MKV_EXTENSIONS.Contains(ResourcePathHelper.GetExtension(mediaItemLocator.NativeResourcePath.FileName)))
                     {
                         await ExtractMkvFanArt(rah.LocalFsResourceAccessor, mediaItemId, title).ConfigureAwait(false);
                     }
                     if (MP4_EXTENSIONS.Contains(ResourcePathHelper.GetExtension(mediaItemLocator.NativeResourcePath.FileName)))
                     {
                         await ExtractTagFanArt(rah.LocalFsResourceAccessor, mediaItemId, title).ConfigureAwait(false);
                     }
                 }
     }
     catch (Exception ex)
     {
         Logger.Warn("VideoFanArtHandler: Exception while reading MKV tag images for '{0}'", ex, mediaItemLocator.NativeResourcePath);
     }
 }
コード例 #16
0
        public async Task <bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool forceQuickMode)
        {
            try
            {
                if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                {
                    return(false);
                }
                if (extractedAspectData.ContainsKey(RecordingAspect.ASPECT_ID))
                {
                    return(false);
                }

                using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                    return(await ExtractMetadataAsync(rah.LocalFsResourceAccessor, extractedAspectData, forceQuickMode).ConfigureAwait(false));
            }
            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("WTVRecordingMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
コード例 #17
0
        /// <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);
            }
        }
コード例 #18
0
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool importOnly, bool forceQuickMode)
        {
            try
            {
                if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                {
                    return(false);
                }

                if (extractedAspectData.ContainsKey(VideoAspect.ASPECT_ID))
                {
                    return(false);
                }

                using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                {
                    if (!rah.LocalFsResourceAccessor.IsFile && rah.LocalFsResourceAccessor.ResourceExists("BDMV"))
                    {
                        using (IFileSystemResourceAccessor fsraBDMV = rah.LocalFsResourceAccessor.GetResource("BDMV"))
                            if (fsraBDMV != null && fsraBDMV.ResourceExists("index.bdmv"))
                            {
                                MultipleMediaItemAspect providerResourceAspect = MediaItemAspect.CreateAspect(extractedAspectData, ProviderResourceAspect.Metadata);
                                // Calling EnsureLocalFileSystemAccess not necessary; only string operation
                                providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, 0);
                                providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_PRIMARY, true);
                                providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "video/bluray"); // BluRay disc
                                providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH, mediaItemAccessor.CanonicalLocalResourcePath.Serialize());

                                // This line is important to keep in, if no VideoAspect is created here, the MediaItems is not detected as Video!
                                SingleMediaItemAspect videoAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, VideoAspect.Metadata);
                                videoAspect.SetAttribute(VideoAspect.ATTR_ISDVD, true);

                                MultipleMediaItemAspect videoStreamAspect = MediaItemAspect.CreateAspect(extractedAspectData, VideoStreamAspect.Metadata);
                                videoStreamAspect.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, 0);
                                videoStreamAspect.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, -1);

                                MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata);
                                mediaAspect.SetAttribute(MediaAspect.ATTR_ISVIRTUAL, false);

                                using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                                {
                                    BDInfoExt bdinfo = new BDInfoExt(rah.LocalFsResourceAccessor.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);
            }
        }
コード例 #19
0
        public virtual async Task <bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool forceQuickMode)
        {
            try
            {
                IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;
                if (fsra == null)
                {
                    return(false);
                }

                if (!extractedAspectData.ContainsKey(VideoAspect.ASPECT_ID))
                {
                    return(false);
                }

                if (forceQuickMode)
                {
                    return(false);
                }

                if (fsra.IsFile)
                {
                    string filePath = fsra.ResourcePathName;

                    using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                    {
                        ILocalFsResourceAccessor lfsra = rah.LocalFsResourceAccessor;
                        if (lfsra != null)
                        {
                            int extSubtitles    = FindExternalSubtitles(lfsra, extractedAspectData);
                            int existsSubtitles = extractedAspectData.Count(d => d.Key == SubtitleAspect.ASPECT_ID);

                            if (!SkipOnlineSearches && extSubtitles == 0 && existsSubtitles == 0)
                            {
                                SubtitleInfo subtitle = new SubtitleInfo();
                                subtitle.FromMetadata(extractedAspectData);

                                var sys = ServiceRegistration.Get <ISystemResolver>();
                                subtitle.MediaFiles.Add(new ResourceLocator(sys.LocalSystemId, mediaItemAccessor.CanonicalLocalResourcePath));

                                List <SubtitleInfo> matches = new List <SubtitleInfo>();
                                if (extractedAspectData.ContainsKey(MovieAspect.ASPECT_ID))
                                {
                                    foreach (var category in subtitle.Categories)
                                    {
                                        matches.AddRange(await OnlineMatcherService.Instance.FindMatchingMovieSubtitlesAsync(subtitle, ImportLanguageCultures.ToList(), category).ConfigureAwait(false));
                                    }
                                }
                                else if (extractedAspectData.ContainsKey(EpisodeAspect.ASPECT_ID))
                                {
                                    foreach (var category in subtitle.Categories)
                                    {
                                        matches.AddRange(await OnlineMatcherService.Instance.FindMatchingEpisodeSubtitlesAsync(subtitle, ImportLanguageCultures.ToList(), category).ConfigureAwait(false));
                                    }
                                }

                                if (matches.Count > 0)
                                {
                                    //Order by language and ranking
                                    var subtitles = matches.OrderBy(s => s.LanguageMatchRank).OrderByDescending(s => s.MatchPercentage);
                                    if (subtitles?.Count() > 0)
                                    {
                                        //Download for each language
                                        foreach (var lang in subtitles.Select(s => s.LanguageMatchRank).Distinct().OrderBy(i => i))
                                        {
                                            var sub = subtitles.FirstOrDefault(s => s.LanguageMatchRank == lang);
                                            if (sub != null)
                                            {
                                                await OnlineMatcherService.Instance.DownloadSubtitleAsync(subtitle, false);
                                            }
                                        }
                                    }
                                }
                            }

                            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("SubtitleMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", e, mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
コード例 #20
0
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool importOnly, bool forceQuickMode)
        {
            string fileName = mediaItemAccessor.ResourceName;

            if (!HasImageExtension(fileName))
            {
                return(false);
            }

            bool refresh = false;

            if (extractedAspectData.ContainsKey(ImageAspect.ASPECT_ID))
            {
                refresh = true;
            }

            try
            {
                IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;
                if (!refresh)
                {
                    MultipleMediaItemAspect providerResourceAspect = MediaItemAspect.CreateAspect(extractedAspectData, ProviderResourceAspect.Metadata);
                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, 0);
                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_PRIMARY, true);

                    if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                    {
                        return(false);
                    }

                    // Open a stream for media item to detect mimeType.
                    using (Stream mediaStream = fsra.OpenRead())
                    {
                        string mimeType = MimeTypeDetector.GetMimeType(mediaStream) ?? DEFAULT_MIMETYPE;
                        providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, mimeType);
                        providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_SIZE, fsra.Size);
                    }
                }

                MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata);
                mediaAspect.SetAttribute(MediaAspect.ATTR_ISVIRTUAL, false);
                MediaItemAspect imageAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ImageAspect.Metadata);

                if (!refresh)
                {
                    // 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);
                        }
                    }

                    byte[] thumbData;
                    // We only want to create missing thumbnails here, so check for existing ones first
                    if (MediaItemAspect.TryGetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, out thumbData) && thumbData != null)
                    {
                        return(true);
                    }

                    using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                        using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                        {
                            string localFsResourcePath = rah.LocalFsResourceAccessor.LocalFileSystemPath;
                            if (localFsResourcePath != null)
                            {
                                // Thumbnail extraction
                                IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();
                                ImageType           imageType;
                                if (generator.GetThumbnail(localFsResourcePath, true, out thumbData, out imageType))
                                {
                                    MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
                                }
                            }
                        }
                    return(true);
                }
                else
                {
                    bool   updated   = false;
                    double?latitude  = imageAspect.GetAttributeValue <double?>(ImageAspect.ATTR_LATITUDE);
                    double?longitude = imageAspect.GetAttributeValue <double?>(ImageAspect.ATTR_LONGITUDE);
                    if (IncludeGeoLocationDetails && !importOnly && latitude.HasValue && longitude.HasValue &&
                        string.IsNullOrEmpty(imageAspect.GetAttributeValue <string>(ImageAspect.ATTR_COUNTRY)))
                    {
                        CivicAddress locationInfo;
                        if (!forceQuickMode && GeoLocationService.Instance.TryLookup(new GeoCoordinate(latitude.Value, 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);
                            updated = true;
                        }
                    }

                    byte[] thumbData;
                    // We only want to create missing thumbnails here, so check for existing ones first
                    if (MediaItemAspect.TryGetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, out thumbData) && thumbData != null)
                    {
                        return(updated);
                    }

                    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>();
                                ImageType           imageType;
                                if (generator.GetThumbnail(localFsResourcePath, cachedOnly, out thumbData, out imageType))
                                {
                                    MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
                                    updated = true;
                                }
                            }
                        }
                    return(updated);
                }
            }
            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);
        }
コード例 #21
0
        private async void TranscodeProcessor(object args)
        {
            FFMpegTranscodeThreadData data = (FFMpegTranscodeThreadData)args;
            bool isStream = data.Context.Live && !data.Context.Segmented;
            bool isFile   = true;
            bool isSlimTv = false;

            try
            {
                if (data.Context.Segmented == true)
                {
                    await FFMpegPlaylistManifest.CreatePlaylistFilesAsync(data.TranscodeData).ConfigureAwait(false);
                }

                int  liveChannelId = 0;
                bool runProcess    = true;
                using (IResourceAccessor mediaAccessor = data.TranscodeData.GetFirstResourceAccessor())
                {
                    if (mediaAccessor is ITranscodeLiveAccessor tla)
                    {
                        isSlimTv      = true;
                        liveChannelId = tla.ChannelId;
                    }
                }

                data.Context.Start();
                data.TranscodeData.ClearRuntimeResourcePaths();
                int exitCode = -1;

                string identifier = "Transcode_" + data.TranscodeData.ClientId;
                if (isSlimTv)
                {
                    var result = await _slimtTvHandler.StartTuningAsync(identifier, liveChannelId).ConfigureAwait(false);

                    if (!result.Success)
                    {
                        _logger.Error("FFMpegMediaConverter: Transcoder unable to start timeshifting for channel {0}", liveChannelId);
                        runProcess = false;
                        exitCode   = 5000;
                    }
                    else
                    {
                        using (var mediaAccessor = await _slimtTvHandler.GetDefaultAccessorAsync(liveChannelId).ConfigureAwait(false))
                        {
                            if (mediaAccessor is INetworkResourceAccessor)
                            {
                                int mediaStreamIndex = data.TranscodeData.FirstResourceIndex;
                                data.TranscodeData.AddRuntimeResourcePath(ResourcePath.Deserialize(data.TranscodeData.InputMediaFilePaths[mediaStreamIndex]), mediaAccessor.CanonicalLocalResourcePath.Serialize());
                            }
                            else
                            {
                                _logger.Error("FFMpegMediaConverter: Transcoder unable to start timeshifting for channel {0} because no URL was found", liveChannelId);
                                runProcess = false;
                                exitCode   = 5001;
                            }
                        }
                    }
                }

                ResourcePath firstPath;
                using (var mediaAccessor = data.TranscodeData.GetFirstResourceAccessor())
                {
                    firstPath = mediaAccessor.CanonicalLocalResourcePath;
                    if (mediaAccessor is INetworkResourceAccessor)
                    {
                        isFile = false;
                    }
                }

                if (runProcess)
                {
                    //Prepare resources
                    List <IDisposable> disposables = new List <IDisposable>();
                    foreach (var res in data.TranscodeData.GetResourceAccessors())
                    {
                        if (!(res is INetworkResourceAccessor))
                        {
                            var rah = new LocalFsResourceAccessorHelper(res);
                            data.TranscodeData.AddRuntimeResourcePath(res.CanonicalLocalResourcePath, rah.LocalFsResourceAccessor.LocalFileSystemPath);
                            var accessToken = rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess();
                            if (accessToken != null)
                            {
                                disposables.Add(accessToken);
                            }
                            disposables.Add(rah);
                        }

                        disposables.Add(res);
                    }

                    ProcessStartInfo startInfo = new ProcessStartInfo()
                    {
                        FileName               = data.TranscodeData.TranscoderBinPath,
                        WorkingDirectory       = data.TranscodeData.WorkPath,
                        Arguments              = data.TranscodeData.TranscoderArguments,
                        UseShellExecute        = false,
                        CreateNoWindow         = true,
                        RedirectStandardOutput = true,
                        RedirectStandardError  = true,
                        RedirectStandardInput  = true,
                        StandardOutputEncoding = Encoding.UTF8,
                        StandardErrorEncoding  = Encoding.UTF8
                    };

                    _logger.Debug("FFMpegMediaConverter: Transcoder '{0}' invoked with command line arguments '{1}'", data.TranscodeData.TranscoderBinPath, data.TranscodeData.TranscoderArguments);

                    IntPtr userToken = IntPtr.Zero;
                    try
                    {
                        //TODO: Fix usages of obsolete and deprecated methods when alternative is available
#if !TRANSCODE_CONSOLE_TEST
                        using (ServiceRegistration.Get <IImpersonationService>().CheckImpersonationFor(firstPath))
                        {
                            //Only when the server is running as a service it will have elevation rights
                            using (ImpersonationProcess ffmpeg = new ImpersonationProcess {
                                StartInfo = startInfo
                            })
                            {
                                if (isFile && !ImpersonationHelper.GetTokenByProcess(out userToken, true))
                                {
                                    return;
                                }
#else
                        {
                            using (Process ffmpeg = new Process()
                            {
                                StartInfo = startInfo
                            })
                            {
#endif
                                ffmpeg.EnableRaisingEvents = true; //Enable raising events because Process does not raise events by default.
                                if (isStream == false)
                                {
                                    ffmpeg.OutputDataReceived += data.Context.OutputDataReceived;
                                }

                                ffmpeg.ErrorDataReceived += data.Context.ErrorDataReceived;
#if !TRANSCODE_CONSOLE_TEST
                                if (isFile)
                                {
                                    ffmpeg.StartAsUser(userToken);
                                }
                                else
                                {
                                    ffmpeg.Start();
                                }
#else
                                ffmpeg.Start();
#endif
                                ffmpeg.BeginErrorReadLine();
                                if (isStream == false)
                                {
                                    ffmpeg.BeginOutputReadLine();
                                }
                                else
                                {
                                    data.TranscodeData.LiveStream = ffmpeg.StandardOutput.BaseStream;
                                }

                                RunTranscodingProcess(ffmpeg, data, isStream);

                                ffmpeg.WaitForExit();
                                exitCode = ffmpeg.ExitCode;
                                ffmpeg.Close();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        if (isStream || data.TranscodeData.OutputFilePath == null)
                        {
                            _logger.Error("FFMpegMediaConverter: Transcoder command failed for stream '{0}'", ex, data.TranscodeData.TranscodeId);
                        }
                        else
                        {
                            _logger.Error("FFMpegMediaConverter: Transcoder command failed for file '{0}'", ex, data.TranscodeData.OutputFilePath);
                        }

                        data.Context.Fail();
                    }
                    finally
                    {
#if !TRANSCODE_CONSOLE_TEST
                        if (userToken != IntPtr.Zero)
                        {
                            NativeMethods.CloseHandle(userToken);
                        }
#endif
                        data.TranscodeData.LiveStream?.Dispose();
                        foreach (var disposable in disposables)
                        {
                            disposable?.Dispose();
                        }
                    }
                }

                if (exitCode > 0)
                {
                    data.Context.Fail();
                }
                else
                {
                    data.Context.Stop();
                }
                _ffMpegEncoderHandler.EndEncoding(data.TranscodeData.Encoder, data.TranscodeData.TranscodeId);

                if (isSlimTv)
                {
                    if (await _slimtTvHandler.EndTuningAsync(identifier).ConfigureAwait(false) == false)
                    {
                        _logger.Error("FFMpegMediaConverter: Transcoder unable to stop timeshifting for channel {0}", liveChannelId);
                    }
                }

                string filePath = data.Context.TargetFile;
                bool   isFolder = false;
                if (string.IsNullOrEmpty(data.Context.SegmentDir) == false)
                {
                    filePath = data.Context.SegmentDir;
                    isFolder = true;
                }

                if (exitCode > 0 || data.Context.Aborted)
                {
                    if (exitCode > 0)
                    {
                        if (isStream || data.TranscodeData.OutputFilePath == null)
                        {
                            _logger.Debug("FFMpegMediaConverter: Transcoder command failed with error {1} for stream '{0}'", data.TranscodeData.TranscodeId, exitCode);
                        }
                        else
                        {
                            _logger.Debug("FFMpegMediaConverter: Transcoder command failed with error {1} for file '{0}'", data.TranscodeData.OutputFilePath, exitCode);
                        }
                    }

                    if (data.Context.Aborted)
                    {
                        if (isStream || data.TranscodeData.OutputFilePath == null)
                        {
                            _logger.Debug("FFMpegMediaConverter: Transcoder command aborted for stream '{0}'", data.TranscodeData.TranscodeId);
                        }
                        else
                        {
                            _logger.Debug("FFMpegMediaConverter: Transcoder command aborted for file '{0}'", data.TranscodeData.OutputFilePath);
                        }
                    }
                    else
                    {
                        _logger.Debug("FFMpegMediaConverter: FFMpeg error \n {0}", data.Context.ConsoleErrorOutput);
                    }

                    data.Context.DeleteFiles();
                }
                else
                {
                    //Touch cache files so they will not be cleaned up
                    if (isFolder == false)
                    {
                        TouchFile(filePath);
                    }
                    else
                    {
                        TouchDirectory(filePath);
                    }
                }
            }
            catch (Exception ex)
            {
                if (isStream || data.TranscodeData.OutputFilePath == null)
                {
                    _logger.Error("FFMpegMediaConverter: Transcoder failed processing '{0}'", ex, data.TranscodeData.TranscodeId);
                }
                else
                {
                    _logger.Error("FFMpegMediaConverter: Transcoder failed processing file '{0}'", ex, data.TranscodeData.OutputFilePath);
                }
            }
            finally
            {
                await RemoveTranscodeContextAsync(data.TranscodeData.ClientId, data.TranscodeData.TranscodeId, data.Context).ConfigureAwait(false);
            }
        }
コード例 #22
0
        /// <summary>
        /// Adds the TsReader filter to the graph.
        /// </summary>
        protected override void AddSourceFilter()
        {
            var platform = IntPtr.Size > 4 ? "x64" : "x86";

            _sourceFilter = FilterLoader.LoadFilterFromDll($"{platform}\\TsReader.ax", typeof(TsReader).GUID, true);
            var baseFilter = _sourceFilter.GetFilter();

            IFileSourceFilter fileSourceFilter = (IFileSourceFilter)baseFilter;

            _tsReader = (ITsReader)baseFilter;
            _tsReader.SetRelaxedMode(1);
            _tsReader.SetTsReaderCallback(this);
            _tsReader.SetRequestAudioChangeCallback(this);

            _graphBuilder.AddFilter(baseFilter, TSREADER_FILTER_NAME);

            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, baseFilter, OnAfterGraphRebuild)
            {
                PlayerName = PlayerTitle
            };
        }
コード例 #23
0
        public override async Task <MetadataContainer> ParseMediaStreamAsync(IEnumerable <IResourceAccessor> mediaResources)
        {
            bool isImage       = true;
            bool isFileSystem  = false;
            bool isNetwork     = false;
            bool isUnsupported = false;

            //Check all files
            if (!mediaResources.Any())
            {
                throw new ArgumentException($"FFMpegMediaAnalyzer: Resource list is empty", "mediaResources");
            }

            foreach (var res in mediaResources)
            {
                if (res is IFileSystemResourceAccessor fileRes)
                {
                    isFileSystem = true;
                    if (!fileRes.IsFile)
                    {
                        throw new ArgumentException($"FFMpegMediaAnalyzer: Resource '{res.ResourceName}' is not a file", "mediaResources");
                    }
                }
                else if (res is INetworkResourceAccessor urlRes)
                {
                    isNetwork = true;
                }
                else
                {
                    isUnsupported = true;
                }
            }

            if (isFileSystem && isNetwork)
            {
                throw new ArgumentException($"FFMpegMediaAnalyzer: Resources are of mixed media formats", "mediaResources");
            }

            if (isUnsupported)
            {
                throw new ArgumentException($"FFMpegMediaAnalyzer: Resources are of unsupported media formats", "mediaResources");
            }

            ProcessExecutionResult executionResult = null;
            string logFileName = "?";

            if (isFileSystem)
            {
                List <LocalFsResourceAccessorHelper> helpers = new List <LocalFsResourceAccessorHelper>();
                List <IDisposable> accessors = new List <IDisposable>();
                try
                {
                    MetadataContainer info = null;
                    logFileName = mediaResources.First().ResourceName;

                    //Initialize and check file system resources
                    foreach (var res in mediaResources)
                    {
                        string resName = res.ResourceName;
                        if (!(HasImageExtension(resName) || HasVideoExtension(resName) || HasAudioExtension(resName) || HasOpticalDiscFileExtension(resName)))
                        {
                            throw new ArgumentException($"FFMpegMediaAnalyzer: Resource '{res.ResourceName}' has unsupported file extension", "mediaResources");
                        }

                        if (!(HasImageExtension(resName)))
                        {
                            isImage = false;
                        }

                        //Ensure availability
                        var rah = new LocalFsResourceAccessorHelper(res);
                        helpers.Add(rah);
                        var accessor = rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess();
                        if (accessor != null)
                        {
                            accessors.Add(accessor);
                        }
                    }

                    string fileName;
                    if (helpers.Count > 1) //Check if concatenation needed
                    {
                        fileName = $"concat:\"{string.Join("|", helpers.Select(h => h.LocalFsResourceAccessor.LocalFileSystemPath))}\"";
                    }
                    else
                    {
                        fileName = $"\"{helpers.First().LocalFsResourceAccessor.LocalFileSystemPath}\"";
                    }

                    string arguments = "";
                    if (isImage)
                    {
                        //Default image decoder (image2) fails if file name contains å, ø, ö etc., so force format to image2pipe
                        arguments = string.Format("-threads {0} -f image2pipe -i {1}", _analyzerMaximumThreads, fileName);
                    }
                    else
                    {
                        arguments = string.Format("-threads {0} -i {1}", _analyzerMaximumThreads, fileName);
                    }

                    //Use first file for parsing. The other files are expected to be of same encoding and same location
                    var firstFile = helpers.First().LocalFsResourceAccessor;
                    executionResult = await ParseFileAsync(helpers.First().LocalFsResourceAccessor, arguments);

                    if (executionResult != null && executionResult.Success && executionResult.ExitCode == 0 && !string.IsNullOrEmpty(executionResult.StandardError))
                    {
                        //_logger.Debug("MediaAnalyzer: Successfully ran FFProbe:\n {0}", executionResult.StandardError);
                        info = new MetadataContainer();
                        info.AddEdition(Editions.DEFAULT_EDITION);
                        info.Metadata[Editions.DEFAULT_EDITION].Size = helpers.Sum(h => h.LocalFsResourceAccessor.Size);
                        FFMpegParseFFMpegOutput.ParseFFMpegOutput(firstFile, executionResult.StandardError, ref info, _countryCodesMapping);

                        // Special handling for files like OGG which will be falsely identified as videos
                        if (info.Metadata[0].VideoContainerType != VideoContainer.Unknown && info.Video[0].Codec == VideoCodec.Unknown)
                        {
                            info.Metadata[0].VideoContainerType = VideoContainer.Unknown;
                        }

                        if (info.IsImage(Editions.DEFAULT_EDITION) || HasImageExtension(fileName))
                        {
                            info.Metadata[Editions.DEFAULT_EDITION].Mime = MimeDetector.GetFileMime(firstFile, "image/unknown");
                        }
                        else if (info.IsVideo(Editions.DEFAULT_EDITION) || HasVideoExtension(fileName))
                        {
                            info.Metadata[Editions.DEFAULT_EDITION].Mime = MimeDetector.GetFileMime(firstFile, "video/unknown");
                            await _probeLock.WaitAsync();

                            try
                            {
                                FFMpegParseH264Info.ParseH264Info(firstFile, info, _h264MaxDpbMbs, H264_TIMEOUT_MS);
                            }
                            finally
                            {
                                _probeLock.Release();
                            }
                            FFMpegParseMPEG2TSInfo.ParseMPEG2TSInfo(firstFile, info);
                        }
                        else if (info.IsAudio(Editions.DEFAULT_EDITION) || HasAudioExtension(fileName))
                        {
                            info.Metadata[Editions.DEFAULT_EDITION].Mime = MimeDetector.GetFileMime(firstFile, "audio/unknown");
                        }
                        else
                        {
                            return(null);
                        }

                        return(info);
                    }
                }
                finally
                {
                    foreach (var accessor in accessors)
                    {
                        accessor?.Dispose();
                    }
                    foreach (var helper in helpers)
                    {
                        helper?.Dispose();
                    }
                }

                if (executionResult != null)
                {
                    _logger.Error("FFMpegMediaAnalyzer: Failed to extract media type information for resource '{0}', Result: {1}, ExitCode: {2}, Success: {3}", logFileName, executionResult.StandardError, executionResult.ExitCode, executionResult.Success);
                }
                else
                {
                    _logger.Error("FFMpegMediaAnalyzer: Failed to extract media type information for resource '{0}', Execution result empty", logFileName);
                }
            }
            else if (isNetwork)
            {
                //We can only read one network resource so take the first
                var    urlRes = mediaResources.First() as INetworkResourceAccessor;
                string url    = urlRes.URL;

                string arguments = "";
                if (url.StartsWith("rtsp://", StringComparison.InvariantCultureIgnoreCase) == true)
                {
                    arguments += "-rtsp_transport tcp ";
                }
                arguments += "-analyzeduration " + _analyzerStreamTimeout + " ";

                //Resolve host first because ffprobe can hang when resolving host
                var resolvedUrl = UrlHelper.ResolveHostToIPv4Url(url);
                if (string.IsNullOrEmpty(resolvedUrl))
                {
                    throw new InvalidOperationException($"FFMpegMediaAnalyzer: Failed to resolve host for resource '{url}'");
                }
                arguments += string.Format("-i \"{0}\"", resolvedUrl);

                executionResult = await ParseUrlAsync(url, arguments);

                if (executionResult != null && executionResult.Success && executionResult.ExitCode == 0 && !string.IsNullOrEmpty(executionResult.StandardError))
                {
                    //_logger.Debug("MediaAnalyzer: Successfully ran FFProbe:\n {0}", executionResult.StandardError);
                    MetadataContainer info = new MetadataContainer();
                    info.AddEdition(Editions.DEFAULT_EDITION);
                    info.Metadata[Editions.DEFAULT_EDITION].Size = 0;
                    FFMpegParseFFMpegOutput.ParseFFMpegOutput(urlRes, executionResult.StandardError, ref info, _countryCodesMapping);

                    // Special handling for files like OGG which will be falsely identified as videos
                    if (info.Metadata[Editions.DEFAULT_EDITION].VideoContainerType != VideoContainer.Unknown && info.Video[Editions.DEFAULT_EDITION].Codec == VideoCodec.Unknown)
                    {
                        info.Metadata[Editions.DEFAULT_EDITION].VideoContainerType = VideoContainer.Unknown;
                    }

                    if (info.IsImage(Editions.DEFAULT_EDITION))
                    {
                        info.Metadata[Editions.DEFAULT_EDITION].Mime = MimeDetector.GetUrlMime(url, "image/unknown");
                    }
                    else if (info.IsVideo(Editions.DEFAULT_EDITION))
                    {
                        info.Metadata[Editions.DEFAULT_EDITION].Mime = MimeDetector.GetUrlMime(url, "video/unknown");
                        await _probeLock.WaitAsync();

                        try
                        {
                            FFMpegParseH264Info.ParseH264Info(urlRes, info, _h264MaxDpbMbs, H264_TIMEOUT_MS);
                        }
                        finally
                        {
                            _probeLock.Release();
                        }
                        FFMpegParseMPEG2TSInfo.ParseMPEG2TSInfo(urlRes, info);
                    }
                    else if (info.IsAudio(Editions.DEFAULT_EDITION))
                    {
                        info.Metadata[Editions.DEFAULT_EDITION].Mime = MimeDetector.GetUrlMime(url, "audio/unknown");
                    }
                    else
                    {
                        return(null);
                    }
                    return(info);
                }

                if (executionResult != null)
                {
                    _logger.Error("FFMpegMediaAnalyzer: Failed to extract media type information for resource '{0}', Result: {1}, ExitCode: {2}, Success: {3}", url, executionResult.StandardError, executionResult.ExitCode, executionResult.Success);
                }
                else
                {
                    _logger.Error("FFMpegMediaAnalyzer: Failed to extract media type information for resource '{0}', Execution result empty", url);
                }
            }

            return(null);
        }
コード例 #24
0
        protected override async Task <bool> ConvertSubtitleFileAsync(string clientId, VideoTranscoding video, double timeStart, string transcodingFile, SubtitleStream sourceSubtitle, SubtitleStream res)
        {
            SubtitleCodec targetCodec = video.TargetSubtitleCodec;

            if (targetCodec == SubtitleCodec.Unknown)
            {
                targetCodec = sourceSubtitle.Codec;
            }

            string tempFile          = null;
            FFMpegTranscodeData data = new FFMpegTranscodeData(_cachePath)
            {
                TranscodeId = video.TranscodeId + "_sub", ClientId = clientId
            };

            if (string.IsNullOrEmpty(video.TranscoderBinPath) == false)
            {
                data.TranscoderBinPath = video.TranscoderBinPath;
            }
            if (string.IsNullOrEmpty(video.TranscoderArguments) == false)
            {
                // TODO: not sure if this is working
                data.TranscoderArguments = video.TranscoderArguments;
                data.InputMediaFilePaths.Add(0, res.SourcePath);
                data.InputArguments.Add(0, new List <string>());
            }
            else
            {
                tempFile = transcodingFile + ".tmp";
                res      = await ConvertSubtitleEncodingAsync(res, tempFile, video.TargetSubtitleCharacterEncoding).ConfigureAwait(false);

                // TODO: not sure if this is working
                _ffMpegCommandline.InitTranscodingParameters(false, new Dictionary <int, string> {
                    { 0, res.SourcePath }
                }, ref data);
                data.InputArguments[0].Add(string.Format("-f {0}", FFMpegGetSubtitleContainer.GetSubtitleContainer(sourceSubtitle.Codec)));
                if (timeStart > 0)
                {
                    data.OutputArguments.Add(string.Format(CultureInfo.InvariantCulture, "-ss {0:0.0}", timeStart));
                }

                res.Codec = targetCodec;
                string subtitleEncoder = "copy";
                if (res.Codec == SubtitleCodec.Unknown)
                {
                    res.Codec = SubtitleCodec.Ass;
                }

                if (sourceSubtitle.Codec != res.Codec)
                {
                    subtitleEncoder = FFMpegGetSubtitleContainer.GetSubtitleContainer(res.Codec);
                }

                string subtitleFormat = FFMpegGetSubtitleContainer.GetSubtitleContainer(res.Codec);
                data.OutputArguments.Add("-vn");
                data.OutputArguments.Add("-an");
                data.OutputArguments.Add(string.Format("-c:s {0}", subtitleEncoder));
                data.OutputArguments.Add(string.Format("-f {0}", subtitleFormat));
            }
            data.OutputFilePath = transcodingFile;

            _logger.Debug("FFMpegMediaConverter: Invoking transcoder to transcode subtitle file '{0}' for transcode '{1}'", res.SourcePath, data.TranscodeId);
            bool success = false;
            var  path    = ResourcePath.Deserialize(res.SourcePath);

            if (path.TryCreateLocalResourceAccessor(out var subRes))
            {
                using (var rah = new LocalFsResourceAccessorHelper(subRes))
                    using (var access = rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                    {
                        var result = await FFMpegBinary.FFMpegExecuteWithResourceAccessAsync(rah.LocalFsResourceAccessor, data.TranscoderArguments, ProcessPriorityClass.Normal, _transcoderTimeout).ConfigureAwait(false);

                        success = result.Success;
                    }
            }
            if (success && File.Exists(transcodingFile) == true)
            {
                if (tempFile != null && File.Exists(tempFile))
                {
                    File.Delete(tempFile);
                }
                res.SourcePath = LocalFsResourceProviderBase.ToProviderPath(transcodingFile);
                return(true);
            }
            return(false);
        }
コード例 #25
0
        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);
                            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);
        }