예제 #1
0
        /// <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);
        }
예제 #2
0
        // 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.");
        }
예제 #3
0
        // 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.");
        }
예제 #4
0
        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());
                                                                }
        }
예제 #5
0
        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());
                                                                }
        }