/// <summary> /// Wires up the various image processing components. /// </summary> protected virtual void ConfigurePipeline() { Console.WriteLine("Preparing pipeline."); VideoCaptureHandler = new CircularBufferCaptureHandler(4000000, AppConfig.Get.LocalPath, "h264"); MotionCaptureHandler = new FrameBufferCaptureHandler(); SnapshotCaptureHandler = new FrameBufferCaptureHandler(directory: AppConfig.Get.LocalPath, extension: "jpg", fileDateTimeFormat: Program.FILENAME_DATE_FORMAT); Splitter = new MMALSplitterComponent(); Resizer = new MMALIspComponent(); VideoEncoder = new MMALVideoEncoder(); SnapshotEncoder = new MMALImageEncoder(continuousCapture: true); Resizer.ConfigureOutputPort <VideoPort>(0, new MMALPortConfig(MMALEncoding.RGB24, MMALEncoding.RGB24, width: 640, height: 480), MotionCaptureHandler); VideoEncoder.ConfigureOutputPort(new MMALPortConfig(MMALEncoding.H264, MMALEncoding.I420, quality: 10, MMALVideoEncoder.MaxBitrateLevel4), VideoCaptureHandler); SnapshotEncoder.ConfigureOutputPort(new MMALPortConfig(MMALEncoding.JPEG, MMALEncoding.I420, quality: 90), SnapshotCaptureHandler); Cam.Camera.VideoPort.ConnectTo(Splitter); Splitter.Outputs[0].ConnectTo(Resizer); Splitter.Outputs[1].ConnectTo(VideoEncoder); Splitter.Outputs[2].ConnectTo(SnapshotEncoder); }
// motion without raw recording, decouple from onDetect event static async Task motion(int totalSeconds, int recordSeconds, int sensitivity) { DeleteFiles(ramdiskPath, "*.h264"); DeleteFiles(ramdiskPath, "*.raw"); var cam = GetConfiguredCamera(); // No longer cut-and-paste from the MMALSharp wiki: // The built-in MotionConfig "recordingTime" argument only applies to calling StartRecording // on the motion buffer, which is RAW (and huge). That also means the onStopDetect action // for cam.WithMotionDetection is not especially useful. So this variation doesn't record the // RAW stream and instead uses a token timeout to terminate the recording. // When using H.264 encoding we require key frames to be generated for the Circular buffer capture handler. MMALCameraConfig.InlineHeaders = true; Console.WriteLine("Preparing pipeline..."); using (var splitter = new MMALSplitterComponent()) { // Two capture handlers are being used here, one for motion detection and the other to record a H.264 stream. using var vidCaptureHandler = new CircularBufferCaptureHandler(4000000, "/media/ramdisk", "h264"); using var motionCircularBufferCaptureHandler = new CircularBufferCaptureHandler(4000000, "/media/ramdisk", "raw"); using var resizer = new MMALIspComponent(); using var vidEncoder = new MMALVideoEncoder(); using var renderer = new MMALVideoRenderer(); cam.ConfigureCameraSettings(); var splitterPortConfig = new MMALPortConfig(MMALEncoding.OPAQUE, MMALEncoding.I420, 0, 0, null); var vidEncoderPortConfig = new MMALPortConfig(MMALEncoding.H264, MMALEncoding.I420, 0, MMALVideoEncoder.MaxBitrateLevel4, null); // The ISP resizer is being used for better performance. Frame difference motion detection will only work if using raw video data. Do not encode to H.264/MJPEG. // Resizing to a smaller image may improve performance, but ensure that the width/height are multiples of 32 and 16 respectively to avoid cropping. var resizerPortConfig = new MMALPortConfig(MMALEncoding.RGB24, MMALEncoding.RGB24, 640, 480, 0, 0, 0, false, null); splitter.ConfigureInputPort(new MMALPortConfig(MMALEncoding.OPAQUE, MMALEncoding.I420), cam.Camera.VideoPort, null); splitter.ConfigureOutputPort(0, splitterPortConfig, null); splitter.ConfigureOutputPort(1, splitterPortConfig, null); resizer.ConfigureOutputPort <VideoPort>(0, resizerPortConfig, motionCircularBufferCaptureHandler); vidEncoder.ConfigureInputPort(new MMALPortConfig(MMALEncoding.OPAQUE, MMALEncoding.I420), splitter.Outputs[1], null); vidEncoder.ConfigureOutputPort(vidEncoderPortConfig, vidCaptureHandler); cam.Camera.VideoPort.ConnectTo(splitter); cam.Camera.PreviewPort.ConnectTo(renderer); splitter.Outputs[0].ConnectTo(resizer); splitter.Outputs[1].ConnectTo(vidEncoder); Console.WriteLine("Camera warmup..."); await Task.Delay(2000); Console.WriteLine($"Detecting motion for {totalSeconds} seconds with sensitivity threshold {sensitivity}..."); var cts = new CancellationTokenSource(TimeSpan.FromSeconds(totalSeconds)); // The recording duration doesn't matter; see notes at top of this method. var motionConfig = new MotionConfig(TimeSpan.FromSeconds(10), sensitivity); // Stephen Cleary says CTS disposal is unnecessary as long as you cancel! https://stackoverflow.com/a/19005066/152997 var startRecordingCTS = LocalPrepareToRecord(); await cam.WithMotionDetection( motionCircularBufferCaptureHandler, motionConfig, // This callback will be invoked when motion has been detected. () => { // This has no effect if the token is already cancelled. startRecordingCTS.Cancel(); }) .ProcessAsync(cam.Camera.VideoPort, cts.Token); CancellationTokenSource LocalPrepareToRecord() { var cts = new CancellationTokenSource(); cts.Token.Register(LocalStartRecording); return(cts); } async void LocalStartRecording() { Console.WriteLine($"Motion detected, recording {recordSeconds} seconds..."); motionCircularBufferCaptureHandler.DisableMotionDetection(); vidCaptureHandler.StartRecording(); vidEncoder.RequestIFrame(); // Prepare to record // Stephen Cleary says CTS disposal is unnecessary as long as you cancel! https://stackoverflow.com/a/19005066/152997 var recordingCTS = new CancellationTokenSource(); // When the token expires, stop recording and re-enable capture recordingCTS.Token.Register(LocalEndRecording); // Start the clock recordingCTS.CancelAfter(recordSeconds * 1000); // Record until the duration passes or the overall motion detection token expires await Task.WhenAny(new Task[] { cts.Token.AsTask(), recordingCTS.Token.AsTask() }); if (!recordingCTS.IsCancellationRequested) { recordingCTS.Cancel(); } } void LocalEndRecording() { Console.WriteLine("...recording stopped."); startRecordingCTS = LocalPrepareToRecord(); motionCircularBufferCaptureHandler.EnableMotionDetection(); vidCaptureHandler.StopRecording(); vidCaptureHandler.Split(); } } // can't use the convenient fall-through using or MMALCamera.Cleanup // throws: Argument is invalid. Unable to destroy component cam.Cleanup(); Console.WriteLine("Exiting."); }
// motion as in the wiki (records raw file) static async Task motion_record_raw(int totalSeconds, int recordSeconds, int sensitivity) { DeleteFiles(ramdiskPath, "*.h264"); DeleteFiles(ramdiskPath, "*.raw"); var cam = GetConfiguredCamera(); // When using H.264 encoding we require key frames to be generated for the Circular buffer capture handler. MMALCameraConfig.InlineHeaders = true; Console.WriteLine("Preparing pipeline..."); using (var splitter = new MMALSplitterComponent()) { // Two capture handlers are being used here, one for motion detection and the other to record a H.264 stream. using var vidCaptureHandler = new CircularBufferCaptureHandler(4000000, "/media/ramdisk", "h264"); using var motionCircularBufferCaptureHandler = new CircularBufferCaptureHandler(4000000, "/media/ramdisk", "raw"); using var resizer = new MMALIspComponent(); using var vidEncoder = new MMALVideoEncoder(); using var renderer = new MMALVideoRenderer(); cam.ConfigureCameraSettings(); // The ISP resizer is being used for better performance. Frame difference motion detection will only work if using raw video data. Do not encode to H.264/MJPEG. // Resizing to a smaller image may improve performance, but ensure that the width/height are multiples of 32 and 16 respectively to avoid cropping. var resizerPortConfig = new MMALPortConfig(MMALEncoding.RGB24, MMALEncoding.RGB24, 640, 480, 0, 0, 0, false, null); var vidEncoderPortConfig = new MMALPortConfig(MMALEncoding.H264, MMALEncoding.I420, 0, MMALVideoEncoder.MaxBitrateLevel4, null); var splitterPortConfig = new MMALPortConfig(MMALEncoding.OPAQUE, MMALEncoding.I420, 0, 0, null); splitter.ConfigureInputPort(new MMALPortConfig(MMALEncoding.OPAQUE, MMALEncoding.I420), cam.Camera.VideoPort, null); splitter.ConfigureOutputPort(0, splitterPortConfig, null); splitter.ConfigureOutputPort(1, splitterPortConfig, null); resizer.ConfigureOutputPort <VideoPort>(0, resizerPortConfig, motionCircularBufferCaptureHandler); vidEncoder.ConfigureInputPort(new MMALPortConfig(MMALEncoding.OPAQUE, MMALEncoding.I420), splitter.Outputs[1], null); vidEncoder.ConfigureOutputPort(vidEncoderPortConfig, vidCaptureHandler); cam.Camera.VideoPort.ConnectTo(splitter); cam.Camera.PreviewPort.ConnectTo(renderer); splitter.Outputs[0].ConnectTo(resizer); splitter.Outputs[1].ConnectTo(vidEncoder); Console.WriteLine("Camera warmup..."); await Task.Delay(2000); var cts = new CancellationTokenSource(TimeSpan.FromSeconds(totalSeconds)); var motionConfig = new MotionConfig(TimeSpan.FromSeconds(recordSeconds), sensitivity); Console.WriteLine($"Detecting motion for {totalSeconds} seconds with sensitivity threshold {sensitivity}..."); await cam.WithMotionDetection( motionCircularBufferCaptureHandler, motionConfig, // This callback will be invoked when motion has been detected. () => { Console.WriteLine($"Motion detected, recording {recordSeconds} seconds..."); // Stop motion detection while we are recording. motionCircularBufferCaptureHandler.DisableMotionDetection(); // Start recording our H.264 video. vidCaptureHandler.StartRecording(); motionCircularBufferCaptureHandler.StartRecording(); // Request a key frame to be immediately generated by the h.264 encoder. vidEncoder.RequestIFrame(); }, // Invoked when motion handler recording-time expires () => { // We want to re-enable the motion detection. motionCircularBufferCaptureHandler.EnableMotionDetection(); // Stop recording on our capture handlers. motionCircularBufferCaptureHandler.StopRecording(); vidCaptureHandler.StopRecording(); // Optionally create new file for our next recording run (don't do the RAW file, we don't want it). vidCaptureHandler.Split(); Console.WriteLine("...recording stopped."); }) .ProcessAsync(cam.Camera.VideoPort, cts.Token); } // can't use the convenient fall-through using or MMALCamera.Cleanup // throws: Argument is invalid. Unable to destroy component cam.Cleanup(); Console.WriteLine("Exiting."); }
public async Task UserProvidedPortName() { TestHelper.BeginTest("UserProvidedPortName"); TestHelper.SetConfigurationDefaults(); TestHelper.CleanDirectory("/home/pi/images/tests"); using (var imgCaptureHandler = new ImageStreamCaptureHandler("/home/pi/images/tests", "jpg")) using (var imgCaptureHandler2 = new ImageStreamCaptureHandler("/home/pi/images/tests", "jpg")) using (var imgCaptureHandler3 = new ImageStreamCaptureHandler("/home/pi/images/tests", "jpg")) using (var imgCaptureHandler4 = new ImageStreamCaptureHandler("/home/pi/images/tests", "jpg")) using (var imgEncoder = new MMALImageEncoder()) using (var imgEncoder2 = new MMALImageEncoder()) using (var imgEncoder3 = new MMALImageEncoder()) using (var imgEncoder4 = new MMALImageEncoder()) using (var splitter = new MMALSplitterComponent()) using (var isp1 = new MMALIspComponent()) using (var isp2 = new MMALIspComponent()) using (var isp3 = new MMALIspComponent()) using (var isp4 = new MMALIspComponent()) using (var nullSink = new MMALNullSinkComponent()) { Fixture.MMALCamera.ConfigureCameraSettings(); var portConfig = new MMALPortConfig(MMALEncoding.JPEG, MMALEncoding.I420, quality: 90, userPortName: "Image encoder 1"); var portConfig2 = new MMALPortConfig(MMALEncoding.JPEG, MMALEncoding.I420, quality: 90, userPortName: "Image encoder 2"); var portConfig3 = new MMALPortConfig(MMALEncoding.JPEG, MMALEncoding.I420, quality: 90, userPortName: "Image encoder 3"); var portConfig4 = new MMALPortConfig(MMALEncoding.JPEG, MMALEncoding.I420, quality: 90, userPortName: "Image encoder 4"); var splitterConfig = new MMALPortConfig(MMALEncoding.I420, MMALEncoding.I420); var resizeConfig = new MMALPortConfig(MMALEncoding.I420, MMALEncoding.I420, width: 1280, height: 720); var resizeConfig2 = new MMALPortConfig(MMALEncoding.I420, MMALEncoding.I420, width: 1024, height: 720); var resizeConfig3 = new MMALPortConfig(MMALEncoding.I420, MMALEncoding.I420, width: 640, height: 480); var resizeConfig4 = new MMALPortConfig(MMALEncoding.I420, MMALEncoding.I420, width: 620, height: 310); // Create our component pipeline. splitter.ConfigureOutputPort <SplitterStillPort>(0, splitterConfig, null); splitter.ConfigureOutputPort <SplitterStillPort>(1, splitterConfig, null); splitter.ConfigureOutputPort <SplitterStillPort>(2, splitterConfig, null); splitter.ConfigureOutputPort <SplitterStillPort>(3, splitterConfig, null); isp1.ConfigureOutputPort(resizeConfig, null); isp2.ConfigureOutputPort(resizeConfig2, null); isp3.ConfigureOutputPort(resizeConfig3, null); isp4.ConfigureOutputPort(resizeConfig4, null); imgEncoder.ConfigureOutputPort(portConfig, imgCaptureHandler); imgEncoder2.ConfigureOutputPort(portConfig2, imgCaptureHandler2); imgEncoder3.ConfigureOutputPort(portConfig3, imgCaptureHandler3); imgEncoder4.ConfigureOutputPort(portConfig4, imgCaptureHandler4); Fixture.MMALCamera.Camera.StillPort.ConnectTo(splitter); Fixture.MMALCamera.Camera.PreviewPort.ConnectTo(nullSink); splitter.Outputs[0].ConnectTo(isp1); splitter.Outputs[1].ConnectTo(isp2); splitter.Outputs[2].ConnectTo(isp3); splitter.Outputs[3].ConnectTo(isp4); isp1.Outputs[0].ConnectTo(imgEncoder); isp2.Outputs[0].ConnectTo(imgEncoder2); isp3.Outputs[0].ConnectTo(imgEncoder3); isp4.Outputs[0].ConnectTo(imgEncoder4); // Camera warm up time await Task.Delay(2000); await Fixture.MMALCamera.ProcessAsync(Fixture.MMALCamera.Camera.StillPort); Fixture.CheckAndAssertFilepath(imgCaptureHandler.GetFilepath()); Fixture.CheckAndAssertFilepath(imgCaptureHandler2.GetFilepath()); Fixture.CheckAndAssertFilepath(imgCaptureHandler3.GetFilepath()); Fixture.CheckAndAssertFilepath(imgCaptureHandler4.GetFilepath()); } }
public async Task TakeMultiplePicturesFromSplitterComponent() { // This test relies on an ISP component being connected between a splitter component output port // and an image encoder input port. If the ISP component is not used as a go-between, the splitter // component appears to only accept 1 of its output ports being connected to an image encoder. I believe // this may be a firmware restriction. TestHelper.BeginTest("TakeMultiplePicturesFromSplitterComponent"); TestHelper.SetConfigurationDefaults(); TestHelper.CleanDirectory("/home/pi/images/tests"); using (var imgCaptureHandler = new ImageStreamCaptureHandler("/home/pi/images/tests", "jpg")) using (var imgCaptureHandler2 = new ImageStreamCaptureHandler("/home/pi/images/tests", "jpg")) using (var imgCaptureHandler3 = new ImageStreamCaptureHandler("/home/pi/images/tests", "jpg")) using (var imgCaptureHandler4 = new ImageStreamCaptureHandler("/home/pi/images/tests", "jpg")) using (var imgEncoder = new MMALImageEncoder()) using (var imgEncoder2 = new MMALImageEncoder()) using (var imgEncoder3 = new MMALImageEncoder()) using (var imgEncoder4 = new MMALImageEncoder()) using (var splitter = new MMALSplitterComponent()) using (var isp1 = new MMALIspComponent()) using (var isp2 = new MMALIspComponent()) using (var isp3 = new MMALIspComponent()) using (var isp4 = new MMALIspComponent()) using (var nullSink = new MMALNullSinkComponent()) { Fixture.MMALCamera.ConfigureCameraSettings(); var portConfig = new MMALPortConfig(MMALEncoding.JPEG, MMALEncoding.I420, quality: 90); var portConfig2 = new MMALPortConfig(MMALEncoding.JPEG, MMALEncoding.I420, quality: 90); var portConfig3 = new MMALPortConfig(MMALEncoding.JPEG, MMALEncoding.I420, quality: 90); var portConfig4 = new MMALPortConfig(MMALEncoding.JPEG, MMALEncoding.I420, quality: 90); var splitterConfig = new MMALPortConfig(MMALEncoding.I420, MMALEncoding.I420); var resizeConfig = new MMALPortConfig(MMALEncoding.I420, MMALEncoding.I420, width: 1280, height: 720); var resizeConfig2 = new MMALPortConfig(MMALEncoding.I420, MMALEncoding.I420, width: 1024, height: 720); var resizeConfig3 = new MMALPortConfig(MMALEncoding.I420, MMALEncoding.I420, width: 640, height: 480); var resizeConfig4 = new MMALPortConfig(MMALEncoding.I420, MMALEncoding.I420, width: 620, height: 310); // Create our component pipeline. splitter.ConfigureOutputPort <SplitterStillPort>(0, splitterConfig, null); splitter.ConfigureOutputPort <SplitterStillPort>(1, splitterConfig, null); splitter.ConfigureOutputPort <SplitterStillPort>(2, splitterConfig, null); splitter.ConfigureOutputPort <SplitterStillPort>(3, splitterConfig, null); isp1.ConfigureOutputPort(resizeConfig, null); isp2.ConfigureOutputPort(resizeConfig2, null); isp3.ConfigureOutputPort(resizeConfig3, null); isp4.ConfigureOutputPort(resizeConfig4, null); imgEncoder.ConfigureOutputPort(portConfig, imgCaptureHandler); imgEncoder2.ConfigureOutputPort(portConfig2, imgCaptureHandler2); imgEncoder3.ConfigureOutputPort(portConfig3, imgCaptureHandler3); imgEncoder4.ConfigureOutputPort(portConfig4, imgCaptureHandler4); Fixture.MMALCamera.Camera.StillPort.ConnectTo(splitter); Fixture.MMALCamera.Camera.PreviewPort.ConnectTo(nullSink); splitter.Outputs[0].ConnectTo(isp1); splitter.Outputs[1].ConnectTo(isp2); splitter.Outputs[2].ConnectTo(isp3); splitter.Outputs[3].ConnectTo(isp4); isp1.Outputs[0].ConnectTo(imgEncoder); isp2.Outputs[0].ConnectTo(imgEncoder2); isp3.Outputs[0].ConnectTo(imgEncoder3); isp4.Outputs[0].ConnectTo(imgEncoder4); // Camera warm up time await Task.Delay(2000); await Fixture.MMALCamera.ProcessAsync(Fixture.MMALCamera.Camera.StillPort); Fixture.CheckAndAssertFilepath(imgCaptureHandler.GetFilepath()); Fixture.CheckAndAssertFilepath(imgCaptureHandler2.GetFilepath()); Fixture.CheckAndAssertFilepath(imgCaptureHandler3.GetFilepath()); Fixture.CheckAndAssertFilepath(imgCaptureHandler4.GetFilepath()); } }