/// <summary>
        /// Performs post-processing tasks on the media object after an optimized file has been created. Specifically,
        /// if the file was successfully created, update the media object instance with information
        /// about the new file. No action is taken if <paramref name="settings" /> is null.
        /// </summary>
        /// <param name="settings">An instance of <see cref="MediaConversionSettings" /> containing
        /// settings and results used in the conversion. May be null.</param>
        private static void OnMediaConversionCompleteOptimizedCreated(MediaConversionSettings settings)
        {
            if (settings == null)
            {
                return;
            }

            var mediaObject = Factory.LoadMediaObjectInstance(settings.MediaObjectId, true);

            // Step 1: Update the media object with info about the newly created file.
            if (settings.FileCreated)
            {
                string msg = String.Format(CultureInfo.CurrentCulture, "FFmpeg created file '{0}'.", Path.GetFileName(settings.FilePathDestination));
                RecordEvent(msg, settings);

                if (mediaObject.GalleryObjectType == GalleryObjectType.Video)
                {
                    var width  = FFmpeg.ParseOutputVideoWidth(settings.FFmpegOutput);
                    var height = FFmpeg.ParseOutputVideoHeight(settings.FFmpegOutput);

                    if (width > int.MinValue)
                    {
                        mediaObject.Optimized.Width = width;
                    }

                    if (height > int.MinValue)
                    {
                        mediaObject.Optimized.Height = height;
                    }
                }
                else
                {
                    mediaObject.Optimized.Width  = settings.TargetWidth;
                    mediaObject.Optimized.Height = settings.TargetHeight;
                }

                // Step 2: If we already had an optimized file and we just created a second one, delete the first one
                // and rename the new one to match the first one.
                var optFileDifferentThanOriginal    = !String.Equals(mediaObject.Optimized.FileName, mediaObject.Original.FileName, StringComparison.InvariantCultureIgnoreCase);
                var optFileDifferentThanCreatedFile = !String.Equals(mediaObject.Optimized.FileName, Path.GetFileName(settings.FilePathDestination), StringComparison.InvariantCultureIgnoreCase);

                if (optFileDifferentThanOriginal && optFileDifferentThanCreatedFile && File.Exists(mediaObject.Optimized.FileNamePhysicalPath))
                {
                    var curFilePath = mediaObject.Optimized.FileNamePhysicalPath;
                    File.Delete(curFilePath);

                    var optFileExtDifferentThanCreatedFileExt = !Path.GetExtension(curFilePath).Equals(Path.GetExtension(settings.FilePathDestination), StringComparison.InvariantCultureIgnoreCase);
                    if (optFileExtDifferentThanCreatedFileExt)
                    {
                        // Extension of created file is different than current optimized file. This can happen, for example, when syncing after
                        // changing encoder settings to produce MP4's instead of FLV's. Use the filename of the current optimized file and combine
                        // it with the extension of the created file.
                        var newOptFileName = String.Concat(Path.GetFileNameWithoutExtension(curFilePath), Path.GetExtension(settings.FilePathDestination));
                        var newOptFilePath = String.Concat(Path.GetDirectoryName(curFilePath), Path.DirectorySeparatorChar, newOptFileName);

                        if (!settings.FilePathDestination.Equals(newOptFilePath, StringComparison.InvariantCultureIgnoreCase))
                        {
                            // Calculated file name differs from the one that was generated, so rename it, deleting any existing file first.
                            if (File.Exists(newOptFilePath))
                            {
                                File.Delete(newOptFilePath);
                            }

                            File.Move(settings.FilePathDestination, newOptFilePath);
                            settings.FilePathDestination = newOptFilePath;
                        }

                        mediaObject.Optimized.FileName             = newOptFileName;
                        mediaObject.Optimized.FileNamePhysicalPath = newOptFilePath;
                    }
                    else
                    {
                        File.Move(settings.FilePathDestination, curFilePath);
                        settings.FilePathDestination = curFilePath;
                    }
                }
                else
                {
                    // We typically get here when the media object is first added.
                    mediaObject.Optimized.FileName             = Path.GetFileName(settings.FilePathDestination);
                    mediaObject.Optimized.FileNamePhysicalPath = settings.FilePathDestination;
                }

                // Now that we have the optimized file name all set, grab it's size.
                int fileSize = (int)(mediaObject.Optimized.FileInfo.Length / 1024);
                mediaObject.Optimized.FileSizeKB = (fileSize < 1 ? 1 : fileSize);                 // Very small files should be 1, not 0.
            }

            // Step 3: Save and finish up.
            mediaObject.LastModifiedByUserName = GlobalConstants.SystemUserName;
            mediaObject.DateLastModified       = DateTime.Now;
            mediaObject.Save();
        }
Exemplo n.º 2
0
        /// <summary>
        /// Execute the FFmpeg utility with the given <paramref name="mediaSettings"/> and return the text output generated by it.
        /// See http://www.ffmpeg.org for documentation.
        /// </summary>
        /// <param name="mediaSettings">The media settings.</param>
        /// <returns>
        /// Returns the text output from the execution of the FFmpeg utility. This data can be parsed to learn more about the media file.
        /// </returns>
        private static string ExecuteFFmpeg(MediaConversionSettings mediaSettings)
        {
            FFmpeg ffmpeg = new FFmpeg(mediaSettings);
            ffmpeg.Execute();
            mediaSettings.FFmpegOutput = ffmpeg.Output;

            return mediaSettings.FFmpegOutput;
        }
Exemplo n.º 3
0
        /// <summary>
        /// Generate the thumbnail image for this display object and save it to the file system. The routine may decide that
        /// a file does not need to be generated, usually because it already exists. However, it will always be
        /// created if the relevant flag is set on the parent <see cref="IGalleryObject" />. (Example: If
        /// <see cref="IGalleryObject.RegenerateThumbnailOnSave" /> = true, the thumbnail file will always be created.) No data is
        /// persisted to the data store.
        /// </summary>
        public void GenerateAndSaveFile()
        {
            // If necessary, generate and save the thumbnail version of the video.
            if (!(IsThumbnailImageRequired()))
            {
                return;                 // No thumbnail image required.
            }

            IGallerySettings gallerySetting = Factory.LoadGallerySetting(_galleryObject.GalleryId);

            // Generate a temporary filename to store the thumbnail created by FFmpeg.
            string tmpVideoThumbnailPath = Path.Combine(AppSetting.Instance.TempUploadDirectory, String.Concat(Guid.NewGuid().ToString(), ".jpg"));

            // Request that FFmpeg create the thumbnail. If successful, the file will be created.
            string ffmpegOutput = FFmpeg.GenerateThumbnail(this._galleryObject.Original.FileNamePhysicalPath, tmpVideoThumbnailPath, gallerySetting.VideoThumbnailPosition, this._galleryObject.GalleryId);

            if (!String.IsNullOrEmpty(ffmpegOutput) && this._galleryObject.IsNew && gallerySetting.ExtractMetadata && this._galleryObject.ExtractMetadataOnSave)
            {
                // When metadata extraction is enabled and we have a new video where we have some output from FFmpeg, parse the data.
                MediaObjectMetadataExtractor metadata = new MediaObjectMetadataExtractor(this._galleryObject.Original.FileNamePhysicalPath, this._galleryObject.GalleryId, ffmpegOutput);
                this._galleryObject.MetadataItems.AddRange(metadata.GetGalleryObjectMetadataItemCollection());
                this._galleryObject.ExtractMetadataOnSave = false;                 // Sends signal to save routine to not re-extract metadata
            }

            // Verify image was created from video, trying again using a different video position setting if necessary.
            ValidateVideoThumbnail(tmpVideoThumbnailPath, gallerySetting.VideoThumbnailPosition);

            // Determine file name and path of the thumbnail image.
            string thumbnailPath = HelperFunctions.MapAlbumDirectoryStructureToAlternateDirectory(this._galleryObject.Original.FileInfo.DirectoryName, gallerySetting.FullThumbnailPath, gallerySetting.FullMediaObjectPath);
            string newFilename   = GenerateNewFilename(thumbnailPath, ImageFormat.Jpeg, gallerySetting.ThumbnailFileNamePrefix);
            string newFilePath   = Path.Combine(thumbnailPath, newFilename);

            int newWidth, newHeight;

            if (File.Exists(tmpVideoThumbnailPath))
            {
                // FFmpeg successfully created a thumbnail image the same size as the video. Now resize it to the width and height we need.
                using (Bitmap originalBitmap = new Bitmap(tmpVideoThumbnailPath))
                {
                    ImageHelper.CalculateThumbnailWidthAndHeight(originalBitmap.Width, originalBitmap.Height, out newWidth, out newHeight, false, gallerySetting.MaxThumbnailLength);

                    // Get JPEG quality value (0 - 100). This is ignored if imgFormat = GIF.
                    int jpegQuality = gallerySetting.ThumbnailImageJpegQuality;

                    // Generate the new image and save to disk.
                    ImageHelper.SaveImageFile(originalBitmap, newFilePath, ImageFormat.Jpeg, newWidth, newHeight, jpegQuality);
                }

                try
                {
                    // Now delete the thumbnail image created by FFmpeg, but no worries if an error happens. The file is in the temp directory
                    // which is cleaned out each time the app starts anyway.
                    File.Delete(tmpVideoThumbnailPath);
                }
                catch (IOException ex)
                {
                    ErrorHandler.Error.Record(ex, this._galleryObject.GalleryId, Factory.LoadGallerySettings(), AppSetting.Instance);
                }
                catch (UnauthorizedAccessException ex)
                {
                    ErrorHandler.Error.Record(ex, this._galleryObject.GalleryId, Factory.LoadGallerySettings(), AppSetting.Instance);
                }
                catch (NotSupportedException ex)
                {
                    ErrorHandler.Error.Record(ex, this._galleryObject.GalleryId, Factory.LoadGallerySettings(), AppSetting.Instance);
                }
            }
            else
            {
                // FFmpeg didn't run or no thumbnail image was created by FFmpeg. Build a generic video thumbnail.
                using (Bitmap originalBitmap = Resources.GenericThumbnailImage_Video)
                {
                    ImageHelper.CalculateThumbnailWidthAndHeight(originalBitmap.Width, originalBitmap.Height, out newWidth, out newHeight, true, gallerySetting.MaxThumbnailLength);

                    // Get JPEG quality value (0 - 100).
                    int jpegQuality = gallerySetting.ThumbnailImageJpegQuality;

                    // Generate the new image and save to disk.
                    ImageHelper.SaveImageFile(originalBitmap, newFilePath, ImageFormat.Jpeg, newWidth, newHeight, jpegQuality);
                }
            }

            this._galleryObject.Thumbnail.Width                = newWidth;
            this._galleryObject.Thumbnail.Height               = newHeight;
            this._galleryObject.Thumbnail.FileName             = newFilename;
            this._galleryObject.Thumbnail.FileNamePhysicalPath = newFilePath;

            int fileSize = (int)(this._galleryObject.Thumbnail.FileInfo.Length / 1024);

            this._galleryObject.Thumbnail.FileSizeKB = (fileSize < 1 ? 1 : fileSize);             // Very small files should be 1, not 0.
        }