public SaveResult Prepare(string filename, double interval) { if (imageDescriptor == null) { throw new NotSupportedException("ImageDescriptor must be set before prepare."); } this.filename = filename; if (writer != null) { writer.Dispose(); } writer = new MJPEGWriter(); VideoInfo info = new VideoInfo(); info.OriginalSize = new Size(imageDescriptor.Width, imageDescriptor.Height); string formatString = FilenameHelper.GetFormatStringCapture(); // If the capture happens at more than 100fps, set the video itself to be at 30fps. // This avoids erratic playback because the player can't cope with the framerate, drawback: prevents review in real time. // FIXME: fix the player so that it can playback high speed video in real time. if (interval < 10) { interval = 1000.0 / 30; } SaveResult result = writer.OpenSavingContext(filename, info, formatString, interval); return(result); }
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; }
public void View_ValidateFilename(string filename) { bool allowEmpty = true; if (!FilenameHelper.IsFilenameValid(filename, allowEmpty)) { ScreenManagerKernel.AlertInvalidFileName(); } }
public SaveResult StartRecord(string filename, double interval) { //----------------------- // Runs on the UI thread. //----------------------- if (imageDescriptor == null) { throw new NotSupportedException("ImageDescriptor must be set before prepare."); } this.filename = filename; if (writer != null) { writer.Dispose(); } writer = new MJPEGWriter(); VideoInfo info = new VideoInfo(); info.OriginalSize = new Size(imageDescriptor.Width, imageDescriptor.Height); bool uncompressed = PreferencesManager.CapturePreferences.SaveUncompressedVideo && imageDescriptor.Format != ImageFormat.JPEG; string formatString = FilenameHelper.GetFormatStringCapture(uncompressed); // If the capture happens too fast or too slow for a regular player, set the video metadata to a more sensible framerate. // This avoids erratic playback because the player can't cope with the framerate, drawback: prevents review in real time. double hrft = PreferencesManager.CapturePreferences.HighspeedRecordingFramerateThreshold; double srft = PreferencesManager.CapturePreferences.SlowspeedRecordingFramerateThreshold; double fps = 1000.0 / interval; double fileInterval = interval; if (fps >= hrft) { double hrfo = PreferencesManager.CapturePreferences.HighspeedRecordingFramerateOutput; fileInterval = 1000.0 / hrfo; log.DebugFormat("High speed recording detected, {0:0.###} fps. Forcing output framerate to {1:0.###} fps.", fps, hrfo); } else if (fps <= srft) { double srfo = PreferencesManager.CapturePreferences.SlowspeedRecordingFramerateOutput; fileInterval = 1000.0 / srfo; log.DebugFormat("Slow speed recording detected, {0:0.###} fps. Forcing output framerate to {1:0.###} fps.", fps, srfo); } log.DebugFormat("Frame budget for writer [{0}]: {1:0.000} ms.", shortId, interval); SaveResult result = writer.OpenSavingContext(filename, info, formatString, imageDescriptor.Format, uncompressed, interval, fileInterval); recording = true; return(result); }
private bool FilePathSanityCheck(string path) { if (cameraGrabber == null) { return(false); } if (!FilenameHelper.IsFilenameValid(path, false)) { ScreenManagerKernel.AlertInvalidFileName(); return(false); } return(true); }
public SaveResult StartRecord(string filename, double interval, ImageRotation rotation) { //----------------------- // Runs on the UI thread. //----------------------- if (imageDescriptor == null) { throw new NotSupportedException("ImageDescriptor must be set before prepare."); } this.filename = filename; if (writer != null) { writer.Dispose(); } writer = new MJPEGWriter(); VideoInfo info = new VideoInfo(); info.OriginalSize = new Size(imageDescriptor.Width, imageDescriptor.Height); bool uncompressed = PreferencesManager.CapturePreferences.SaveUncompressedVideo && imageDescriptor.Format != ImageFormat.JPEG; string formatString = FilenameHelper.GetFormatStringCapture(uncompressed); double fileInterval = CalibrationHelper.ComputeFileFrameInterval(interval); log.DebugFormat("Frame budget for writer [{0}]: {1:0.000} ms.", shortId, interval); SaveResult result = writer.OpenSavingContext(filename, info, formatString, imageDescriptor.Format, uncompressed, interval, fileInterval, rotation); recording = true; return(result); }
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; }