diff --git a/src/MMALSharp.Processing/Handlers/FileStreamCaptureHandler.cs b/src/MMALSharp.Processing/Handlers/FileStreamCaptureHandler.cs
index 3f4f8c74..6bdbd323 100644
--- a/src/MMALSharp.Processing/Handlers/FileStreamCaptureHandler.cs
+++ b/src/MMALSharp.Processing/Handlers/FileStreamCaptureHandler.cs
@@ -9,16 +9,47 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Runtime.CompilerServices;
namespace MMALSharp.Handlers
{
///
/// Processes image data to a .
///
- public class FileStreamCaptureHandler : StreamCaptureHandler, IFileStreamCaptureHandler
+ public class FileStreamCaptureHandler : MemoryStreamCaptureHandler, IFileStreamCaptureHandler
{
private readonly bool _customFilename;
private int _increment;
+ private bool _skippingFirstPartialFrame = true;
+ private bool _continuousCapture;
+
+ ///
+ /// When true, the next full frame will be written. If is not also
+ /// true, this property will be reset to false after writing the image so that only one image is written.
+ ///
+ public bool CaptureNextFrame { get; set; }
+
+ ///
+ /// When true, every frame is written to storage.
+ ///
+ public bool ContinuousCapture
+ {
+ get => _continuousCapture;
+
+ set
+ {
+ _continuousCapture = value;
+ if(_continuousCapture)
+ {
+ CaptureNextFrame = true;
+ }
+ }
+ }
+
+ ///
+ /// Defines the image files' DateTime format string that is applied when the object is constructed with directory and extension arguments.
+ ///
+ public string FilenameDateTimeFormat { get; set; } = "dd-MMM-yy HH-mm-ss";
///
/// A list of files that have been processed by this capture handler.
@@ -36,10 +67,15 @@ public class FileStreamCaptureHandler : StreamCaptureHandler, IFileS
public string Extension { get; set; }
///
- /// The name of the current file associated with the FileStream.
+ /// The filename to write next (if applicable).
///
public string CurrentFilename { get; set; }
+ ///
+ /// The full pathname of the most recently written image file (if any).
+ ///
+ public string LastWrittenPathname { get; set; }
+
///
/// Creates a new instance of the class without provisions for writing to a file. Supports
/// subclasses in which file output is optional.
@@ -51,82 +87,73 @@ public FileStreamCaptureHandler()
///
/// Creates a new instance of the class with the specified directory and filename extension. Filenames will be in the
- /// format "dd-MMM-yy HH-mm-ss" taken from this moment in time.
+ /// format defined by the property.
///
/// The directory to save captured data.
/// The filename extension for saving files.
- public FileStreamCaptureHandler(string directory, string extension)
+ /// When true, every frame is written to a file.
+ public FileStreamCaptureHandler(string directory, string extension, bool continuousCapture = true)
{
this.Directory = directory.TrimEnd('/');
this.Extension = extension.TrimStart('.');
+ this.ContinuousCapture = continuousCapture;
MMALLog.Logger.LogDebug($"{nameof(FileStreamCaptureHandler)} created for directory {this.Directory} and extension {this.Extension}");
System.IO.Directory.CreateDirectory(this.Directory);
-
- var now = DateTime.Now.ToString("dd-MMM-yy HH-mm-ss");
-
- int i = 1;
-
- var fileName = $"{this.Directory}/{now}.{this.Extension}";
-
- while (File.Exists(fileName))
- {
- fileName = $"{this.Directory}/{now} {i}.{this.Extension}";
- i++;
- }
- var fileInfo = new FileInfo(fileName);
-
- this.CurrentFilename = Path.GetFileNameWithoutExtension(fileInfo.Name);
- this.CurrentStream = File.Create(fileName);
+ this.LastWrittenPathname = string.Empty;
+ this.CurrentStream = new MemoryStream();
}
///
- /// Creates a new instance of the class with the specified file path.
+ /// Creates a new instance of the class with the specified file pathname. An auto-incrementing number is added to each
+ /// new filename.
///
/// The absolute full path to save captured data to.
- public FileStreamCaptureHandler(string fullPath)
+ /// When true, every frame is written to a file.
+ public FileStreamCaptureHandler(string fullPath, bool continuousCapture = true)
{
- var fileInfo = new FileInfo(fullPath);
-
- this.Directory = fileInfo.DirectoryName;
- this.CurrentFilename = Path.GetFileNameWithoutExtension(fileInfo.Name);
var ext = fullPath.Split('.').LastOrDefault();
-
if (string.IsNullOrEmpty(ext))
{
throw new ArgumentNullException(nameof(ext), "Could not get file extension from path string.");
}
-
- this.Extension = ext;
- MMALLog.Logger.LogDebug($"{nameof(FileStreamCaptureHandler)} created for directory {this.Directory} and extension {this.Extension}");
+ this.ContinuousCapture = continuousCapture;
+ this.Extension = ext;
+ var fileInfo = new FileInfo(fullPath);
+ this.Directory = fileInfo.DirectoryName;
+ this.CurrentFilename = Path.GetFileNameWithoutExtension(fileInfo.Name);
_customFilename = true;
+ MMALLog.Logger.LogDebug($"{nameof(FileStreamCaptureHandler)} created for pathname {fullPath}");
+
System.IO.Directory.CreateDirectory(this.Directory);
- this.CurrentStream = File.Create(fullPath);
+ this.LastWrittenPathname = string.Empty;
+ this.CurrentStream = new MemoryStream();
}
///
- /// Gets the filename that a FileStream points to.
+ /// Gets the filename of the most recently stored image file.
///
/// The filename.
- public string GetFilename() =>
- (this.CurrentStream != null) ? Path.GetFileNameWithoutExtension(this.CurrentStream.Name) : string.Empty;
+ public string GetFilename() =>
+ (!string.IsNullOrEmpty(this.LastWrittenPathname)) ? Path.GetFileNameWithoutExtension(this.LastWrittenPathname) : string.Empty;
///
- /// Gets the filepath that a FileStream points to.
+ /// Gets the pathname of the most recently stored image file.
///
/// The filepath.
- public string GetFilepath() =>
- this.CurrentStream?.Name ?? string.Empty;
+ public string GetFilepath() =>
+ this.LastWrittenPathname;
///
- /// Creates a new File (FileStream), assigns it to the Stream instance of this class and disposes of any existing stream.
+ /// Outputs the current frame to a file. If a full frame hasn't been captured, a flag is set to capture the frame
+ /// once the end of stream is indicated.
///
public virtual void NewFile()
{
@@ -135,20 +162,24 @@ public virtual void NewFile()
return;
}
- this.CurrentStream?.Dispose();
+ // Wait for EOS
+ if(!CaptureNextFrame)
+ {
+ CaptureNextFrame = true;
+ return;
+ }
- string newFilename = string.Empty;
-
- if (_customFilename)
+ string newFilename;
+ if (!string.IsNullOrEmpty(CurrentFilename))
{
// If we're taking photos from video port, we don't want to be hammering File.Exists as this is added I/O overhead. Camera can take multiple photos per second
// so we can't do this when filename uses the current DateTime.
_increment++;
- newFilename = $"{this.Directory}/{this.CurrentFilename} {_increment}.{this.Extension}";
+ newFilename = $"{this.Directory}/{_customFilename} {_increment}.{this.Extension}";
}
else
{
- string tempFilename = DateTime.Now.ToString("dd-MMM-yy HH-mm-ss");
+ string tempFilename = DateTime.Now.ToString(FilenameDateTimeFormat);
int i = 1;
newFilename = $"{this.Directory}/{tempFilename}.{this.Extension}";
@@ -160,7 +191,34 @@ public virtual void NewFile()
}
}
- this.CurrentStream = File.Create(newFilename);
+ using (FileStream fs = new FileStream(newFilename, FileMode.Create, FileAccess.Write))
+ {
+ this.CurrentStream.WriteTo(fs);
+ }
+
+ this.LastWrittenPathname = newFilename;
+ }
+
+ ///
+ /// If capture is active, output a new file.
+ ///
+ public virtual void NewFrame()
+ {
+ if (_skippingFirstPartialFrame)
+ {
+ _skippingFirstPartialFrame = false;
+ return;
+ }
+
+ if(_continuousCapture || this.CaptureNextFrame)
+ this.NewFile();
+
+ this.CaptureNextFrame = _continuousCapture;
+
+ if (this.CurrentStream != null)
+ {
+ this.CurrentStream.SetLength(0);
+ }
}
///
diff --git a/src/MMALSharp.Processing/Handlers/IFileStreamCaptureHandler.cs b/src/MMALSharp.Processing/Handlers/IFileStreamCaptureHandler.cs
index c708f12c..bfc203a1 100644
--- a/src/MMALSharp.Processing/Handlers/IFileStreamCaptureHandler.cs
+++ b/src/MMALSharp.Processing/Handlers/IFileStreamCaptureHandler.cs
@@ -15,6 +15,11 @@ public interface IFileStreamCaptureHandler : IOutputCaptureHandler
///
void NewFile();
+ ///
+ /// The callback handler has received an end-of-stream marker.
+ ///
+ void NewFrame();
+
///
/// Gets the filepath that a FileStream points to.
///
diff --git a/src/MMALSharp.Processing/Handlers/ImageStreamCaptureHandler.cs b/src/MMALSharp.Processing/Handlers/ImageStreamCaptureHandler.cs
index 9d8599ad..88fbf9a3 100644
--- a/src/MMALSharp.Processing/Handlers/ImageStreamCaptureHandler.cs
+++ b/src/MMALSharp.Processing/Handlers/ImageStreamCaptureHandler.cs
@@ -13,18 +13,22 @@ namespace MMALSharp.Handlers
public class ImageStreamCaptureHandler : FileStreamCaptureHandler
{
///
- /// Creates a new instance of the class with the specified directory and filename extension.
+ /// Creates a new instance of the class with the specified directory and filename extension. Filenames will be in the
+ /// format defined by the property.
///
/// The directory to save captured images.
/// The filename extension for saving files.
- public ImageStreamCaptureHandler(string directory, string extension)
- : base(directory, extension) { }
+ /// When true, every frame is written to a file.
+ public ImageStreamCaptureHandler(string directory, string extension, bool continuousCapture = true)
+ : base(directory, extension, continuousCapture) { }
///
- /// Creates a new instance of the class with the specified file path.
+ /// Creates a new instance of the class with the specified file pathname. An auto-incrementing number is added to each
+ /// new filename.
///
/// The absolute full path to save captured data to.
- public ImageStreamCaptureHandler(string fullPath)
- : base(fullPath) { }
+ /// When true, every frame is written to a file.
+ public ImageStreamCaptureHandler(string fullPath, bool continuousCapture = true)
+ : base(fullPath, continuousCapture) { }
}
}
diff --git a/src/MMALSharp/Callbacks/FastImageOutputCallbackHandler.cs b/src/MMALSharp/Callbacks/FastImageOutputCallbackHandler.cs
index 487b6ea4..735edc93 100644
--- a/src/MMALSharp/Callbacks/FastImageOutputCallbackHandler.cs
+++ b/src/MMALSharp/Callbacks/FastImageOutputCallbackHandler.cs
@@ -32,9 +32,9 @@ public override void Callback(IBuffer buffer)
var eos = buffer.AssertProperty(MMALBufferProperties.MMAL_BUFFER_HEADER_FLAG_FRAME_END) ||
buffer.AssertProperty(MMALBufferProperties.MMAL_BUFFER_HEADER_FLAG_EOS);
- if (eos && this.CaptureHandler is IFileStreamCaptureHandler)
+ if (eos)
{
- ((IFileStreamCaptureHandler)this.CaptureHandler).NewFile();
+ (this.CaptureHandler as IFileStreamCaptureHandler)?.NewFrame();
}
}
}