private void bgWorkerDualSave_DoWork(object sender, DoWorkEventArgs e) { // This is executed in Worker Thread space. (Do not call any UI methods) log.Debug("Saving side by side video."); int threadResult = 0; // Get first frame outside the loop to set up the saving context. long currentTime = 0; Bitmap composite = GetCompositeImage(currentTime); log.DebugFormat("Composite size: {0}.", composite.Size); VideoInfo info = new VideoInfo { ReferenceSize = composite.Size }; string formatString = FilenameHelper.GetFormatString(dualSaveFileName); SaveResult result = videoFileWriter.OpenSavingContext(dualSaveFileName, info, formatString, fileFrameInterval); if (result != SaveResult.Success) { e.Result = 2; return; } videoFileWriter.SaveFrame(composite); composite.Dispose(); while (currentTime < commonTimeline.LastTime && !dualSaveCancelled) { currentTime += commonTimeline.FrameTime; if (bgWorkerDualSave.CancellationPending) { threadResult = 1; dualSaveCancelled = true; break; } composite = GetCompositeImage(currentTime); videoFileWriter.SaveFrame(composite); composite.Dispose(); int percent = (int)((double)currentTime * 100 / commonTimeline.LastTime); bgWorkerDualSave.ReportProgress(percent); } if (!dualSaveCancelled) { threadResult = 0; } e.Result = threadResult; }
private void bgWorkerSave_DoWork(object sender, DoWorkEventArgs e) { Thread.CurrentThread.Name = "Saving"; BackgroundWorker bgWorker = sender as BackgroundWorker; if (!(e.Argument is SavingSettings)) { saveResult = SaveResult.UnknownError; e.Result = 0; return; } SavingSettings settings = (SavingSettings)e.Argument; if (settings.ImageRetriever == null || settings.InputFrameInterval < 0 || bgWorker == null) { saveResult = SaveResult.UnknownError; e.Result = 0; return; } try { log.DebugFormat("Saving selection [{0}]->[{1}] to: {2}", settings.Section.Start, settings.Section.End, Path.GetFileName(settings.File)); // TODO it may actually make more sense to split the saving methods for regular // save, paused video and diaporama. It will cause inevitable code duplication but better encapsulation and simpler algo. // When each save method has its own class and UI panel, it will be a better design. if (!settings.PausedVideo) { // Take special care for slowmotion, the frame interval can not go down indefinitely. // Use frame duplication when under 8fps. settings.Duplication = (int)Math.Ceiling(settings.InputFrameInterval / 125.0); settings.KeyframeDuplication = settings.Duplication; settings.OutputFrameInterval = settings.InputFrameInterval / settings.Duplication; if (settings.KeyframesOnly) { settings.EstimatedTotal = metadata.Count * settings.Duplication; } else { settings.EstimatedTotal = videoReader.EstimatedFrames * settings.Duplication; } } else { // For paused video, slow motion is not supported. // InputFrameInterval will have been set to a multiple of the original frame interval. settings.Duplication = 1; settings.KeyframeDuplication = (int)(settings.InputFrameInterval / metadata.UserInterval); settings.OutputFrameInterval = metadata.UserInterval; long regularFramesTotal = videoReader.EstimatedFrames - metadata.Count; long keyframesTotal = metadata.Count * settings.KeyframeDuplication; settings.EstimatedTotal = regularFramesTotal + keyframesTotal; } log.DebugFormat("interval:{0}, duplication:{1}, kf duplication:{2}", settings.OutputFrameInterval, settings.Duplication, settings.KeyframeDuplication); videoReader.BeforeFrameEnumeration(); IEnumerable <Bitmap> images = EnumerateImages(settings); VideoFileWriter w = new VideoFileWriter(); string formatString = FilenameHelper.GetFormatString(settings.File); saveResult = w.Save(settings, videoReader.Info, formatString, images, bgWorker); videoReader.AfterFrameEnumeration(); } catch (Exception exp) { saveResult = SaveResult.UnknownError; log.Error("Unknown error while saving video."); log.Error(exp.StackTrace); } e.Result = 0; }