コード例 #1
0
        /// <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;
        }
コード例 #2
0
        /// <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;
        }
コード例 #3
0
        /// <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 ();
        }