示例#1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="file"></param>
        /// <param name="progress"></param>
        /// <returns></returns>
        public async Task <MediaJob> Work(FileInfo file, ProgressWorker progress, bool thumb, bool icon)
        {
            MediaJob mediaJobData = new MediaJob();
            Dictionary <string, string> metaData = new Dictionary <string, string>();
            IMediaInfo mediaInfo = await FFmpeg.GetMediaInfo(file.FullName);

            IVideoStream          videoStream      = mediaInfo.VideoStreams.FirstOrDefault();
            IVideoStream          pictureStream    = mediaInfo.VideoStreams.FirstOrDefault();
            string                thumbTempFile    = Path.Combine(Configuration.Get.TempDir, Guid.NewGuid() + "_" + Media.GetThumbName(file));
            string                iconTempFile     = Path.Combine(Configuration.Get.TempDir, Guid.NewGuid() + "_" + Media.GetIconName(file));
            Func <string, string> iconTempFileFunc = (number) => { return("\"" + iconTempFile.Replace("\\", "\\\\") + "\""); };

            // Fill out metadata
            Dictionary <string, string> metaDic = metaDic = Media.GetMeta(file);

            mediaJobData.Title    = metaDic.ContainsKey("Object Name") ? metaDic["Object Name"] : file.Name;
            mediaJobData.Caption  = metaDic.ContainsKey("Caption/Abstract") ? metaDic["Caption"] : mediaJobData.Caption;
            mediaJobData.File     = file;
            mediaJobData.Updated  = file.LastWriteTime;
            mediaJobData.Width    = videoStream.Width;
            mediaJobData.Height   = videoStream.Height;
            mediaJobData.Duration = videoStream.Duration.TotalSeconds;

            // Calculate the thumbnail clip start and length
            double clipStart  = Configuration.Get.Video.ClipStart;
            double clipLength = Configuration.Get.Video.ClipLength;
            double duration   = videoStream.Duration.TotalSeconds;

            if (clipStart + clipLength > duration)
            {
                clipStart = 0;                 // Requested clip exceeds video file's duration
            }
            if (clipStart + clipLength > duration)
            {
                clipLength = duration;                 // Extremely short video file
            }

            // Set up the video thumbnail conversion
            if (thumb)
            {
                Media.Dimension d = Media.GetCroppedThumbnailDimensions(videoStream.Width, videoStream.Height, false);
                mediaJobData.Thumbnail = true;

                IConversion thumbConversion = FFmpeg.Conversions.New()
                                              .AddStream(videoStream)
                                              .SetSeek(TimeSpan.FromSeconds(clipStart))
                                              .SetOutputTime(TimeSpan.FromSeconds(clipLength))
                                              .SetOutputFormat(Format.mp4)
                                              .SetVideoBitrate(60000)
                                              .AddParameter("-s " + ((int)d.Width).ToString() + "x" + ((int)d.Height).ToString())
                                              .AddParameter("-vcodec libx264")
                                              .AddParameter("-pix_fmt yuv420p")
                                              .SetOutput(thumbTempFile);

                // Do the thumbnail conversion
                _ = thumbConversion.Start().ContinueWith((result) =>
                {
                    using (FileStream input = File.OpenRead(thumbTempFile))
                        using (FileStream output = file.GetAlternateDataStream(Media.GetThumbName(file), FileMode.Create).OpenWrite())
                        {
                            int bufferLength = 1024;
                            byte[] buffer    = new byte[bufferLength];
                            int bytesRead    = 0;

                            do
                            {
                                bytesRead = input.Read(buffer, 0, bufferLength);
                                output.Write(buffer, 0, bytesRead);
                            }while (bytesRead != 0);
                        }
                    File.Delete(thumbTempFile);
                    progress.FinishedWork(Media.GetThumbPath(file));
                });
            }

            if (icon)
            {
                mediaJobData.Icon = true;

                // Set up the icon conversion
                pictureStream.SetCodec(VideoCodec.png);
                IConversion iconConversion = FFmpeg.Conversions.New()
                                             .AddStream(pictureStream)
                                             .ExtractNthFrame(1, iconTempFileFunc)
                                             .AddParameter("-s " + (Configuration.Get.Image.Icon.Width).ToString() + "x" + ((int)(((double)Configuration.Get.Image.Icon.Width / (double)videoStream.Width) * (double)videoStream.Height)).ToString());

                // Do the icon conversion
                _ = iconConversion.Start().ContinueWith((result) =>
                {
                    using (FileStream input = File.OpenRead(iconTempFile))
                        using (FileStream output = file.GetAlternateDataStream(Media.GetIconName(file), FileMode.Create).OpenWrite())
                        {
                            int bufferLength = 1024;
                            byte[] buffer    = new byte[bufferLength];
                            int bytesRead    = 0;

                            do
                            {
                                bytesRead = input.Read(buffer, 0, bufferLength);
                                output.Write(buffer, 0, bytesRead);
                            }while (bytesRead != 0);
                        }
                    File.Delete(iconTempFile);
                    progress.FinishedWork(Media.GetIconPath(file));
                });
            }

            // Done
            return(mediaJobData);
        }
示例#2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="file"></param>
        /// <param name="progress"></param>
        /// <returns></returns>
        public async Task <MediaJob> Work(FileInfo file, ProgressWorker progress, bool thumb, bool icon)
        {
            MediaJob mediaJobData = new MediaJob();

            // Load the image and get metadata
            using MagickImage image = new MagickImage(file.FullName);

            mediaJobData.File     = file;
            mediaJobData.Updated  = file.LastWriteTime;
            mediaJobData.Width    = image.Width;
            mediaJobData.Height   = image.Height;
            mediaJobData.Duration = 0;

            Dictionary <string, string> metaDic = metaDic = Media.GetMeta(file);

            mediaJobData.Title   = metaDic.ContainsKey("Object Name") ? metaDic["Object Name"] : file.Name;
            mediaJobData.Caption = metaDic.ContainsKey("Caption/Abstract") ? metaDic["Caption/Abstract"] : mediaJobData.Caption;

            // Make the thumbnail
            if (thumb)
            {
                mediaJobData.Thumbnail = true;

                await Task.Run(() =>
                {
                    Media.Dimension imageCrop = null;

                    if (Configuration.Get.UseFaceDetector)
                    {
                        // Check for faces
                        Media.Dimension face = Media.GetFaceCrop(file, image.Width, image.Height);

                        if (face != null)                         // If a face was detected, put it as the image crop
                        {
                            imageCrop = face;
                        }
                    }

                    if (imageCrop == null)                     // If no image crop is defined, use the default crop
                    {
                        // Compute new dimensions
                        imageCrop = Media.GetCroppedThumbnailDimensions(image.Width, image.Height, true);
                    }

                    // Crop image
                    image.Crop(new MagickGeometry(imageCrop.CropLeft, imageCrop.CropTop, imageCrop.CropWidth, imageCrop.CropHeight));

                    // Resize image to thumbnail
                    MagickGeometry thumbSize    = new MagickGeometry(imageCrop.Width, imageCrop.Height);
                    thumbSize.IgnoreAspectRatio = false;
                    image.Resize(thumbSize);

                    // Write the thumbnail to disk
                    using (FileStream writeStream = file.GetAlternateDataStream(Media.GetThumbName(file), FileMode.Create).OpenWrite())
                    {
                        image.Write(writeStream);
                        writeStream.Close();
                    }

                    progress.FinishedWork(Media.GetThumbName(file));
                });
            }

            if (icon)
            {
                mediaJobData.Icon = true;

                await Task.Run(() =>
                {
                    // Resize image to icon
                    MagickGeometry iconSize    = new MagickGeometry(Configuration.Get.Image.Icon.Width, Configuration.Get.Image.Icon.Height);
                    iconSize.IgnoreAspectRatio = false;
                    image.Resize(iconSize);

                    // Write the icon to disk
                    using (FileStream writeStream = file.GetAlternateDataStream(Media.GetIconName(file), FileMode.Create).OpenWrite())
                    {
                        image.Write(writeStream);
                        writeStream.Close();
                    }

                    progress.FinishedWork(Media.GetIconName(file));
                });
            }

            return(mediaJobData);
        }
示例#3
0
        public SortedDictionary <string, DirItem> Process(bool overwrite)
        {
            bool                               dirty                = false;
            ProgressWorker                     progress             = new ProgressWorker(workDirectory);
            List <Task <MediaJob> >            mediaProcessingTasks = new List <Task <MediaJob> >();
            SortedDictionary <string, DirItem> mediaList            = new SortedDictionary <string, DirItem>(); // New metadata
            SortedDictionary <string, DirItem> mediaListOld         = new SortedDictionary <string, DirItem>(); // Old cached metadata

            if (progress.GetProgress() > 0 && progress.GetProgress() < 100)
            {
                return(null);
            }

            progress.AddWork(workDirectory.FullName);

            // Retrieve existing media list if any
            if (File.Exists(Path.Combine(workDirectory.FullName, Configuration.Get.MetaFile)))
            {
                mediaListOld = JsonSerializer.Deserialize <SortedDictionary <string, DirItem> >(File.ReadAllText(Path.Combine(workDirectory.FullName, Configuration.Get.MetaFile)));
            }

            // List directories in the dir
            foreach (DirectoryInfo dir in workDirectory.GetDirectories())
            {
                // If the dir starts with a $ then we ignore it
                if (dir.Name.StartsWith('$'))
                {
                    continue;
                }

                // Try to identify the icon for a directory. It's basically whatever the first media file found is.
                FileInfo dirIcon = FindFirst(dir);
                if (dirIcon == null)
                {
                    continue;
                }

                string dirName = dirIcon.FullName.Substring(Configuration.Get.GalleryPath.Length + 1).Replace('\\', '/');

                if (!mediaListOld.ContainsKey(dirName) ||              // If the old media list doesn't contain this dir (because it's new), or
                    overwrite)                        // We're instructed to re-generate all data
                {
                    // Update the information about this dir
                    String ext = dirIcon.Extension.ToLower().Trim('.');

                    // An image
                    if (Configuration.Get.Image.Ext.Contains(ext))
                    {
                        progress.AddWork(Media.GetIconPath(dirIcon));
                        ImageWorker worker = new ImageWorker();
                        mediaProcessingTasks.Add(worker.Work(dirIcon, progress, false, true));
                    }

                    // A video
                    if (Configuration.Get.Video.Ext.Contains(ext))
                    {
                        progress.AddWork(Media.GetIconPath(dirIcon));
                        VideoWorker worker = new VideoWorker();
                        mediaProcessingTasks.Add(worker.Work(dirIcon, progress, false, true));
                    }

                    mediaList.Add(dirName, new DirItem
                    {
                        Title   = dir.Name,
                        Type    = "dir",
                        Updated = DateTime.Now
                    });
                }
                else
                {
                    // No updates, simply copy the old data to the new
                    mediaList.Add(dirName, mediaListOld[dirName]);
                }
            }

            // List files in the dir
            foreach (FileInfo file in workDirectory.GetFiles())
            {
                if (!mediaListOld.ContainsKey(file.Name) ||              // If the old media list doesn't contain this file (because it's new), or
                    overwrite)                        // We're instructed to re-generate all data
                {
                    // Update information about this file
                    String ext = file.Extension.ToLower().Trim('.');

                    // An image
                    if (Configuration.Get.Image.Ext.Contains(ext))
                    {
                        progress.AddWork(Media.GetThumbPath(file));
                        ImageWorker worker = new ImageWorker();
                        mediaProcessingTasks.Add(worker.Work(file, progress, true, false));
                    }

                    // A video
                    if (Configuration.Get.Video.Ext.Contains(ext))
                    {
                        progress.AddWork(Media.GetThumbPath(file));
                        VideoWorker worker = new VideoWorker();
                        mediaProcessingTasks.Add(worker.Work(file, progress, true, false));
                    }
                }
                else
                {
                    // No updates, simply copy the old data to the new
                    mediaList.Add(file.Name, mediaListOld[file.Name]);
                }
            }

            // Async job processing
            try
            {
                // For every media processing task initiated above, wait for all of them to complete. They spin off their own
                // encoding jobs that are tracked via ProgressWorker, but should return media metadata relatively quickly
                Task.WaitAll(mediaProcessingTasks.ToArray());

                foreach (Task <MediaJob> task in mediaProcessingTasks)
                {
                    dirty = true;

                    MediaJob mediaJobData = task.Result;
                    string   ext          = mediaJobData.File.Extension.ToLower().Trim('.');
                    string   path         = "";
                    string   type         = "";

                    if (!mediaJobData.Icon)
                    {
                        path = mediaJobData.File.Name;
                        if (Configuration.Get.Image.Ext.Contains(ext))
                        {
                            type = "image";
                        }
                        else if (Configuration.Get.Video.Ext.Contains(ext))
                        {
                            type = "video";
                        }
                        else
                        {
                            type = "unknown";
                        }

                        mediaList.Add(path, new DirItem
                        {
                            Title   = mediaJobData.Title,
                            Type    = type,
                            Updated = DateTime.Now
                        });
                    }

                    using (FileStream fs = mediaJobData.File.GetAlternateDataStream(Configuration.Get.MetaFile, FileMode.OpenOrCreate).OpenWrite())
                    {
                        fs.SetLength(0);
                        fs.Flush();                         // delete the contents of the file first
                        byte[] bytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(new FileMeta()
                        {
                            Caption = mediaJobData.Caption
                        }));
                        fs.Write(bytes, 0, bytes.Length);
                    }
                }
            }
            catch (AggregateException e)
            {
                // Error handling: Log all errors generated by the workers
                StringBuilder sb = new StringBuilder();

                for (int j = 0; j < e.InnerExceptions.Count; j++)
                {
                    progress.FinishedWork("Error");
                    sb.AppendLine("\n-------------------------------------------------\n" + e.InnerExceptions[j].ToString());
                }

                LogManager.GetLogger("DirectoryWorker").Error(sb.ToString());
            }

            // Save our dir list to a file
            if (dirty)
            {
                try
                {
                    File.WriteAllText(Path.Combine(workDirectory.FullName, Configuration.Get.MetaFile), JsonSerializer.Serialize(mediaList));
                }
                catch (IOException e)
                {
                    LogManager.GetLogger("DirectoryWorker").Error(e.ToString());
                }
            }

            progress.FinishedWork(workDirectory.FullName);

            return(mediaList);
        }