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;
    }
Example #3
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
        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;
    }
Example #5
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;
      }
    }
    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;
      }
    }
Example #8
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);
      }

      // 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 };
    }