/// <summary> /// Generates the Detail thumbnail pages. /// </summary> /// <param name="avFiles">The <see cref="AVFileSet"/> to generate /// thumbnails for.</param> /// <param name="displayFilename">The display name of the <see cref="AVFileSet"/>.</param> /// <param name="outTemplate">The template (string format) to use when generating /// output filenames.</param> /// <param name="outputDirectory">The fullpath of the output directory.</param> /// <returns> /// The number of thumbnails created. /// </returns> public int GenerateDetailThumbs(AVFileSet avFiles, string displayFilename, string outTemplate, string outputDirectory) { ThumbnailGrid tgrid = CreateThumbnailGrid (TNSettings.LayoutMode, TNSettings.DetailThumbs, TNSettings.DetailColumns, TNSettings.DetailRows, TNSettings.DetailThreshold); //ThumbnailGrid tgrid = ThumbnailGrid.CreateUsingNRows (layout, _maxDetailRows, _detailColumns, // aspectRatio, _mThreshold); //layout.adjustWidth (tgrid.NColumns, tgrid.ThumbWidth); System.Collections.Generic.IEnumerator<MSEEncoder.AudioVideoFile> avFilesEnumerator = avFiles.GetEnumerator(); avFilesEnumerator.MoveNext(); MSEEncoder.AudioVideoFile avFile = avFilesEnumerator.Current; int avFileNum = 1; bool highlight = avFiles.Count > 1 ? true : false; System.Drawing.Size videoSize = AVFileSet.GetVideoSize(avFile); int nThumbsPerPage = tgrid.NColumns * tgrid.NRows; int nThumbs = (int) ((TNSettings.End - TNSettings.Start).TotalSeconds / TNSettings.Interval.TotalSeconds) + 1; // start adjustment to make thumbnails occur at _interval seconds int nExtraStartSeconds = (int) (TNSettings.Start.TotalSeconds % TNSettings.Interval.TotalSeconds); int nStartIntervals = (int) (TNSettings.Start.TotalSeconds / TNSettings.Interval.TotalSeconds); if (nExtraStartSeconds != 0) { nThumbs++; nStartIntervals++; } int nExtraEndSeconds = (int) (TNSettings.End.TotalSeconds % TNSettings.Interval.TotalSeconds); int nEndIntervals = (int) (TNSettings.End.TotalSeconds / TNSettings.Interval.TotalSeconds); TimeSpan adjustedEnd = TNSettings.End; if (nExtraEndSeconds != 0) { nThumbs++; adjustedEnd = TNSettings.End; //adjustedEnd = new TimeSpan (0, 0, nEndIntervals * // (int) tnSettings.Interval.TotalSeconds); } int nPages = (int) ((float) nThumbs / nThumbsPerPage + 0.5); if (nPages * nThumbsPerPage < nThumbs) nPages++; string stats; if (videoSize.Width != TNSettings.SrcRect.Width || videoSize.Height != TNSettings.SrcRect.Height || Math.Abs ((double) videoSize.Width / videoSize.Height - TNSettings.ThumbAspectRatio) > 0.01) { stats = String.Format ("{0}x{1} ({2:F2}:1) [{3}x{4} ({5:F2}:1)] {6} {7}", TNSettings.SrcRect.Width, TNSettings.SrcRect.Height, TNSettings.ThumbAspectRatio, videoSize.Width, videoSize.Height, (double) videoSize.Width / videoSize.Height, //getAudioStreamStats(mediaItem), GetFileSizeString (avFiles.TotalFileSize), System.IO.File.GetLastWriteTime (avFile.FileName).ToString ("g") ); } else { stats = String.Format ("{0}x{1} ({2:F2}:1) {3} {4}", videoSize.Width, videoSize.Height, TNSettings.ThumbAspectRatio, //getAudioStreamStats(mediaItem), GetFileSizeString (avFiles.TotalFileSize), System.IO.File.GetLastWriteTime (avFile.FileName).ToString ("g") ); } THelper.Information ( "Generating {0} {1}x{2} thumbnails every {3} seconds on {4} {5}x{6} Detail pages.", nThumbs, tgrid.ThumbWidth, tgrid.ThumbHeight, TNSettings.Interval.TotalSeconds, nPages, tgrid.NColumns, tgrid.NRows); ThumbnailMultiWriter mwriter = new ThumbnailMultiWriter (this, tgrid, outputDirectory, displayFilename, outTemplate, avFiles.Count > 1 ? avFiles.Count : 0, TNSettings.Interval, stats, avFiles.TotalDuration, nPages); TimeSpan currentTime = TNSettings.Start; int thumbCount = 0; TimeSpan fileStartTime = new TimeSpan(0,0,0); MSEEncoder.ThumbnailGenerator thumbGenerator = avFile.CreateThumbnailGenerator (videoSize); while (currentTime > fileStartTime + AVFileSet.GetVideoDuration(avFile)) { if (thumbGenerator != null) { thumbGenerator.Dispose(); thumbGenerator = null; } if (!avFilesEnumerator.MoveNext ()) { avFile = null; break; } fileStartTime += AVFileSet.GetVideoDuration(avFile); avFile = avFilesEnumerator.Current; avFileNum++; highlight = true; thumbGenerator = avFile.CreateThumbnailGenerator (videoSize); } if (nExtraStartSeconds != 0 && thumbGenerator != null) { using (System.Drawing.Bitmap resized = GenerateThumbnail (thumbGenerator, currentTime - fileStartTime, tgrid.ThumbWidth, tgrid.ThumbHeight, TNSettings.SrcRect)) { if (avFiles.Count > 1) mwriter.Add (resized, currentTime, highlight, avFileNum, fileStartTime); else mwriter.Add (resized, currentTime, highlight, 0, TimeSpan.Zero); thumbCount++; highlight = false; } currentTime = new TimeSpan (0, 0, 0, 0, (int) (nStartIntervals * TNSettings.Interval.TotalMilliseconds)); } while (currentTime <= adjustedEnd && thumbGenerator != null) { while (currentTime > fileStartTime + AVFileSet.GetVideoDuration(avFile)) { if (thumbGenerator != null) { thumbGenerator.Dispose(); thumbGenerator = null; } if (!avFilesEnumerator.MoveNext ()) { avFile = null; break; } fileStartTime += AVFileSet.GetVideoDuration(avFile); avFile = avFilesEnumerator.Current; avFileNum++; highlight = true; thumbGenerator = avFile.CreateThumbnailGenerator (videoSize); } if (thumbGenerator == null) break; if (BGWorker != null) { if (BGWorker.CancellationPending) { if (thumbGenerator != null) { thumbGenerator.Dispose (); thumbGenerator = null; } mwriter.Close (); return thumbCount; } } using (System.Drawing.Bitmap resized = GenerateThumbnail (thumbGenerator, currentTime - fileStartTime, tgrid.ThumbWidth, tgrid.ThumbHeight, TNSettings.SrcRect)) { if (avFiles.Count > 1) mwriter.Add (resized, currentTime, highlight, avFileNum, fileStartTime); else mwriter.Add (resized, currentTime, highlight, 0, TimeSpan.Zero); thumbCount++; highlight = false; } currentTime += TNSettings.Interval; } if (nExtraEndSeconds != 0 && thumbCount < nThumbs && thumbGenerator != null) { using (System.Drawing.Bitmap resized = GenerateThumbnail (thumbGenerator, TNSettings.End - fileStartTime, tgrid.ThumbWidth, tgrid.ThumbHeight, TNSettings.SrcRect)) { if (avFiles.Count > 1) mwriter.Add (resized, TNSettings.End, highlight, avFileNum, fileStartTime); else mwriter.Add (resized, TNSettings.End, highlight, 0, TimeSpan.Zero); thumbCount++; highlight = false; } } if (thumbGenerator != null) { thumbGenerator.Dispose (); thumbGenerator = null; } mwriter.Close (); return thumbCount; }
/// <summary> /// Generates the overview thumbnail page. /// </summary> /// <param name="avFiles">The <see cref="AVFileSet"/> to generate /// thumbnails for.</param> /// <param name="displayFilename">The display name of the <see cref="AVFileSet"/>.</param> /// <param name="outTemplate">The template (string format) to use when generating /// output filenames.</param> /// <param name="outputDirectory">The fullpath of the output directory.</param> /// <returns>The number of thumbnails created.</returns> public int GenerateOverviewThumbs(AVFileSet avFiles, string displayFilename, string outTemplate, string outputDirectory) { ThumbnailGrid tgrid = CreateThumbnailGrid (TNSettings.LayoutMode, TNSettings.OverviewThumbs, TNSettings.OverviewColumns, TNSettings.OverviewRows, TNSettings.OverviewThreshold); System.Collections.Generic.IEnumerator<MSEEncoder.AudioVideoFile> avFilesEnumerator = avFiles.GetEnumerator(); avFilesEnumerator.MoveNext(); MSEEncoder.AudioVideoFile avFile = avFilesEnumerator.Current; int avFileNum = 1; bool highlight = avFiles.Count > 1 ? true : false; System.Drawing.Size videoSize = AVFileSet.GetVideoSize (avFile); #if true string stats; if (videoSize.Width != TNSettings.SrcRect.Width || videoSize.Height != TNSettings.SrcRect.Height || Math.Abs ((double) videoSize.Width / videoSize.Height - TNSettings.ThumbAspectRatio) > 0.01) { stats = String.Format ("{0}x{1} ({2:F2}:1) [{3}x{4} ({5:F2}:1)] {6} {7}", TNSettings.SrcRect.Width, TNSettings.SrcRect.Height, TNSettings.ThumbAspectRatio, videoSize.Width, videoSize.Height, (double) videoSize.Width / videoSize.Height, //getAudioStreamStats(mediaItem), GetFileSizeString (avFiles.TotalFileSize), System.IO.File.GetLastWriteTime (avFile.FileName).ToString ("g") ); } else { stats = String.Format ("{0}x{1} ({2:F2}:1) {3} {4}", videoSize.Width, videoSize.Height, TNSettings.ThumbAspectRatio, //getAudioStreamStats(mediaItem), GetFileSizeString (avFiles.TotalFileSize), System.IO.File.GetLastWriteTime (avFile.FileName).ToString ("g") ); } #else string stats = String.Format ("{0}x{1} ({2:F2}:1) [{3}x{4} {5}x{6}] {7} {8}", videoSize.Width, videoSize.Height, (double) videoSize.Width / videoSize.Height, //getAudioStreamStats(mediaItem), tgrid.ThumbWidth, tgrid.ThumbHeight, tgrid.NColumns, tgrid.NRows, GetFileSizeString (mediaItem.MainMediaFile.FileSize), System.IO.File.GetLastWriteTime (displayFilename).ToString ("g") ); #endif THelper.Information ("Generating {0} {1}x{2} thumbnails on a {3}x{4} Overview page.", tgrid.NThumbs, tgrid.ThumbWidth, tgrid.ThumbHeight, tgrid.NColumns, tgrid.NRows); ThumbnailWriter writer = new ThumbnailWriter (this, tgrid, outputDirectory, displayFilename, outTemplate, avFiles.Count > 1 ? avFiles.Count : 0, stats, avFiles.TotalDuration); double intervalSeconds = ((TNSettings.End.TotalSeconds - TNSettings.Start.TotalSeconds) / (tgrid.NColumns * tgrid.NRows - 1)); int milliseconds = (int) ((intervalSeconds - Math.Truncate (intervalSeconds)) * 1000 + 0.5); TimeSpan interval = new TimeSpan (0, 0, 0, (int) intervalSeconds, milliseconds); int nThumbsAdded = 0; TimeSpan currentTime = TNSettings.Start; TimeSpan fileStartTime = new TimeSpan(0,0,0); MSEEncoder.ThumbnailGenerator thumbGenerator = avFile.CreateThumbnailGenerator (videoSize); while (currentTime <= TNSettings.End) { while (currentTime > fileStartTime + AVFileSet.GetVideoDuration(avFile)) { if (thumbGenerator != null) { thumbGenerator.Dispose(); thumbGenerator = null; } if (!avFilesEnumerator.MoveNext ()) { avFile = null; break; } fileStartTime += AVFileSet.GetVideoDuration(avFile); avFile = avFilesEnumerator.Current; avFileNum++; highlight = true; thumbGenerator = avFile.CreateThumbnailGenerator (videoSize); } if (thumbGenerator == null) break; if (BGWorker != null) { if (BGWorker.CancellationPending) { if (thumbGenerator != null) { thumbGenerator.Dispose (); thumbGenerator = null; } writer.Close (); return nThumbsAdded; } } using (System.Drawing.Bitmap resized = GenerateThumbnail (thumbGenerator, currentTime - fileStartTime, tgrid.ThumbWidth, tgrid.ThumbHeight, TNSettings.SrcRect)) { if (avFiles.Count > 1) writer.Add (resized, currentTime, highlight, avFileNum); else writer.Add (resized, currentTime, highlight, 0); highlight = false; nThumbsAdded++; } currentTime += interval; } // Last thumb should always be end time. if (nThumbsAdded < tgrid.NThumbs && thumbGenerator != null) { using (System.Drawing.Bitmap resized = GenerateThumbnail (thumbGenerator, TNSettings.End - fileStartTime, tgrid.ThumbWidth, tgrid.ThumbHeight, TNSettings.SrcRect)) { if (avFiles.Count > 1) writer.Add (resized, TNSettings.End, highlight, avFileNum); else writer.Add (resized, TNSettings.End, highlight, 0); nThumbsAdded++; } } if (thumbGenerator != null) { thumbGenerator.Dispose (); thumbGenerator = null; } writer.Close (); return tgrid.NThumbs; }
/// <summary> /// Generate thumbnail pages for the set of video files in list. /// </summary> /// <param name="filenames">A list of video files. Only a single /// thumbnail set is generated. Multiple files are /// treated as one long video.</param> /// <param name="displayFilename">The display filename to use for the video file /// set.</param> /// <param name="outputDirectory">The output directory.</param> private void ProcessFiles(List<string> filenames, string displayFilename, string outputDirectory) { DateTime startTime = DateTime.Now; AVFileSet avFiles = new AVFileSet (); MSEEncoder.AudioVideoFile avFile; DateTime tempStart, tempEnd; foreach (string filename in filenames) { try { THelper.Information ("Processing {0} ...", filename); tempStart = DateTime.Now; avFile = new MSEEncoder.AudioVideoFile (filename); tempEnd = DateTime.Now; THelper.Debug ("{0} to create Microsoft.Encoder.AudioVideoFile.", (tempEnd - tempStart).ToString (@"h\:mm\:ss\.ff")); } catch (MSEEncoder.InvalidMediaFileException) { THelper.Critical ("\"" + filename + "\" isn't a video file."); return; } tempStart = DateTime.Now; MSEEncoder.MediaItem mediaItem = new MSEEncoder.MediaItem (avFile); tempEnd = DateTime.Now; THelper.Debug ("{0} to create Microsoft.Encoder.MediaItem.", (tempEnd - tempStart).ToString (@"h\:mm\:ss\.ff")); bool hasVideo = (mediaItem.OriginalFileType & MSEEncoder.FileType.Video) == MSEEncoder.FileType.Video; if (!hasVideo) { THelper.Critical ("\"" + filename + "\" isn't a video file."); return; } tempStart = DateTime.Now; avFile.CalculateDuration (AVFileSet.IndexProgessHandler); Console.Write ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); tempEnd = DateTime.Now; THelper.Debug ("{0} to run CalculateDuration.", (tempEnd - tempStart).ToString (@"h\:mm\:ss\.ff")); THelper.Debug ("AudioVideoFile.Duration {0} {1}.", avFile.Duration.ToString (@"h\:mm\:ss\.ffff"), filename); THelper.Debug ("VideoStream.Duration {0} {1}.", AVFileSet.GetVideoDuration(avFile).ToString (@"h\:mm\:ss\.ffff"), filename); THelper.Debug ("AudioStream.Duration {0} {1}.", AVFileSet.GetAudioDuration(avFile).ToString (@"h\:mm\:ss\.ffff"), filename); THelper.Debug ("AudioStream channels = {0} {1}.", AVFileSet.GetAudioChannels(avFile), filename); avFiles.Add (avFile); } avFiles.UpdateTotals (); DateTime avFileSetCreated = DateTime.Now; THelper.Information ("{0} Total time to create AVFileSet.", (avFileSetCreated - startTime).ToString (@"h\:mm\:ss")); THelper.Debug ("Using {0} Layout Mode.", _tnSettings.LayoutMode); if (_tnSettings.End == TimeSpan.Zero) _tnSettings.End = avFiles.TotalDuration; else if (_tnSettings.End < TimeSpan.Zero) _tnSettings.End = avFiles.TotalDuration + _tnSettings.End; else if (_tnSettings.End > avFiles.TotalDuration) _tnSettings.End = avFiles.TotalDuration; THelper.Information ( "Thumbnails Range {0} -> {1}", _tnSettings.Start.ToString(@"h\:mm\:ss\.fff"), _tnSettings.End.ToString (@"h\:mm\:ss\.fff")); THelper.Information ("Thumbnail Duration {0} (Total {1})", (_tnSettings.End - _tnSettings.Start).ToString(@"h\:mm\:ss\.fff"), avFiles.TotalDuration.ToString (@"h\:mm\:ss\.fff")); avFile = avFiles[0]; System.Drawing.Size videoSize = AVFileSet.GetVideoSize(avFile); if (outputDirectory != null) THelper.Information ("OutputDirectory is \"{0}\"", outputDirectory); string baseDirectory = outputDirectory; if (outputDirectory == null) { outputDirectory = ThumbnailCreator.GetDirectoryName (avFile.FileName); baseDirectory = outputDirectory; if (_tnSettings.SubDirectory.Length > 0) { outputDirectory = System.IO.Path.Combine (outputDirectory, _tnSettings.SubDirectory); if (!System.IO.Directory.Exists (outputDirectory)) System.IO.Directory.CreateDirectory (outputDirectory); } } if (displayFilename == null) displayFilename = avFiles.GetDisplayName (baseDirectory); ThumbnailCreator creator; DateTime overviewCreated; int nThumbs; int originalBorder = _tnSettings.Border; _tnSettings.SrcRect = new System.Drawing.Rectangle (0, 0, videoSize.Width, videoSize.Height); double videoAspect = (double) videoSize.Width / videoSize.Height; _tnSettings.ThumbAspectRatio = videoAspect; THelper.Debug ("Video Frame Size {0}x{1} ({2:F2})", videoSize.Width, videoSize.Height, videoAspect); bool manualSrcRect = false; if (_srcRect.Width != 0 && _srcRect.Height != 0) { _tnSettings.SetSrcRect (_srcRect); manualSrcRect = true; THelper.Information ("Changing video rectangle from 0,0+{0}x{1} to {2},{3}+{4}x{5}", videoSize.Width, videoSize.Height, _srcRect.X, _srcRect.Y, _srcRect.Width, _srcRect.Height); } else if (_cropAspect != 0.0) { _tnSettings.AdjustThumbAspectRatio (_cropAspect, videoAspect, videoSize); manualSrcRect = true; THelper.Information ("Cropping aspect ratio from {0:F3} to {1:F3}", videoAspect, _cropAspect); } if (_stretchAspect != 0.0) { _tnSettings.ThumbAspectRatio = _stretchAspect; manualSrcRect = true; THelper.Information ("Stretching aspect ratio from {0:F3} to {1:F3}", videoAspect, _stretchAspect); } if (!manualSrcRect && _autoAspectRatio) { double displayAspect = AVFileSet.GetAspectRatio(avFile); if (Math.Abs(videoAspect - displayAspect) > 0.05) { //if (displayAspect > videoAspect) // displayAspect -= 0.01; //else // displayAspect += 0.01; _tnSettings.AdjustThumbAspectRatio (displayAspect, videoAspect, videoSize); THelper.Information ("Auto adjusting aspect ratio from {0:F3} to {1:F3}", videoAspect, displayAspect); } } string outTemplate; if (_createOverview) { //_tnSettings.Border = 1; creator = new ThumbnailCreator (_tnSettings, null); outTemplate = System.IO.Path.GetFileNameWithoutExtension (displayFilename) + "_overview.jpg"; nThumbs = creator.GenerateOverviewThumbs (avFiles, displayFilename, outTemplate, outputDirectory); overviewCreated = DateTime.Now; THelper.Information ("{0} to create Overview thumbnails.", (overviewCreated - avFileSetCreated).ToString (@"h\:mm\:ss")); THelper.Information ("{0} thumbnails created. {1:F2} seconds / thumbnail.", nThumbs, (overviewCreated - avFileSetCreated).TotalSeconds / nThumbs); } else { overviewCreated = DateTime.Now; THelper.Information ("Overview page skipped."); } _tnSettings.Border = originalBorder; if (_tnSettings.Interval.TotalSeconds > 0) { nThumbs = 0; creator = new ThumbnailCreator (_tnSettings, null); TimeSpan originalInterval = _tnSettings.Interval; if (_autoInterval) { IEnumerator<KeyValuePair<int,int>> ranges = _autoIntervals.GetEnumerator (); ranges.MoveNext (); KeyValuePair<int,int> range = ranges.Current; int interval = range.Value; int maxInterval = interval; double totalMinutes = (_tnSettings.End - _tnSettings.Start).TotalMinutes; while (ranges.MoveNext ()) { range = ranges.Current; if (totalMinutes < range.Key) { THelper.Information ("Duration {0:F2} < {1} minutes. AutoInterval is {2} seconds.", totalMinutes, range.Key, range.Value); interval = range.Value; break; } } _tnSettings.Interval = new TimeSpan (0, 0, interval); if (interval == maxInterval) THelper.Information ("Duration {0:F2} > {1} minutes. AutoInterval is {2} seconds", totalMinutes, range.Key, interval); } outTemplate = System.IO.Path.GetFileNameWithoutExtension (displayFilename); outTemplate = outTemplate.Replace ("{", "("); outTemplate = outTemplate.Replace ("}", ")"); outTemplate = outTemplate + "_page{0:D4}.jpg"; nThumbs = creator.GenerateDetailThumbs (avFiles, displayFilename, outTemplate, outputDirectory); _tnSettings.Interval = originalInterval; DateTime detailsCreated = DateTime.Now; if (nThumbs > 0) { THelper.Information ("{0} to generate Detail page thumbnails.", (detailsCreated - overviewCreated).ToString (@"h\:mm\:ss")); THelper.Information ("{0} thumbnails created. {1:F2} seconds / thumbnail.", nThumbs, (detailsCreated - overviewCreated).TotalSeconds / nThumbs); } } else { THelper.Information ("Detail page thumbnails skipped."); } DateTime overall = DateTime.Now; THelper.Information ("{0} overall time to process {1}.", (overall - startTime).ToString (@"h\:mm\:ss"), displayFilename); THelper.Information (); }