sskodje / ScreenRecorderLib

A .NET library for screen recording in Windows, using native Microsoft Media Foundation for realtime encoding to h264 video or PNG images.
MIT License
408 stars 93 forks source link

How can i instead of saving to files, dump the data on a list of Bitmaps? #314

Open ZephyrDogma opened 1 month ago

ZephyrDogma commented 1 month ago

I need to dump the data on Bitmaps to then use on a app, how can i do this without, saving to file, then processing each file created etc, etc...

sskodje commented 3 weeks ago

If you mean record to pictures/slideshow, there is only support for recording to files. But you can take snapshots while recording video to a stream.

ZephyrDogma commented 2 weeks ago

my apologies but once again how does one record the video to a stream, it seems the version 6.2.0 doesn't have ability to record to stream, or perhaps there is and that isn't shown in the guide

sskodje commented 2 weeks ago

You can just pass a Stream reference instead of a file path, like so:

var outStream = new MemoryStream();
var rec = Recorder.CreateRecorder(RecorderOptions.DefaultMainMonitor));
rec.Record(outStream);

To take snapshots while recording a video, you can do like this:

var outStream = new MemoryStream();
bool snapshotResult = rec.TakeSnapshot(outStream);
ZephyrDogma commented 1 week ago

Thank you very much, now that i came back to this topic i'm very happy with your solution, thanks a lot!

ZephyrDogma commented 1 day ago

So i have run into an issue, this is my code and it seems i get an System.ArgumentException: 'Parameter is not valid.' on the constructor of the Bitmap class, would you be so kind as to explain how one should properly handle the stream used in the recorder in order to process it into a normal Bitmap?

private void TimerScreenShot_Tick(object sender, ElapsedEventArgs e)
        {
            recorder.TakeSnapshot(stream);

            using (var bitmap = new Bitmap((Stream)stream))
            {
                // Process the bitmap as needed
                // For example, save to a different location or send over a network
                Application.Current.Dispatcher.Invoke(() =>
                {
                    stream.Position = 0;

                    System.Windows.Media.Imaging.BitmapImage bitmapImage = new System.Windows.Media.Imaging.BitmapImage();
                    bitmapImage.BeginInit();
                    bitmapImage.CacheOption = System.Windows.Media.Imaging.BitmapCacheOption.OnLoad;
                    bitmapImage.StreamSource = stream;
                    bitmapImage.EndInit();
                });
                // Here you can perform other operations with the bitmap
                // For example, send the bitmap over a network or manipulate it in memory
            }
        }``
ZephyrDogma commented 15 hours ago

So now i have got this, and it seems like the image created as a result doesn't create the image correctly, am i doing something wrong or is there a recomended way to using this stream, being that stream is the one i pass when i do recorder.Record(stream) and snapStream is the one i use in the snapshot:

private void TimerScreenShot_Tick(object sender, ElapsedEventArgs e)
        {
lock (mlockTimer)
            {
                MemoryStream snapStream = new MemoryStream();
                Console.WriteLine("Stream size is: " + stream.Length);

                recorder.TakeSnapshot(snapStream);

                Console.WriteLine("SnapStream size is: " + snapStream.Length);

                byte[] data = new byte[snapStream.Length];
                snapStream.Read(data, 0, (int)snapStream.Length);

                Console.WriteLine("Data size is: " + data.Length);
                File.WriteAllBytes("output_image.jpg", data);

                Console.WriteLine("Image saved to " + "output_image.jpg");
            }

        }

image_2024-09-27_104923534 As you can see from the image it complains that it doesnt support this file format, but when i record instead with a referece to a stream i do slideshow with a string path it creates the jpgs correctly

sskodje commented 15 hours ago

Hi! It looks like you are not rewinding "snapStream" before readinging the data. Try this and see if it works:

byte[] data = new byte[snapStream.Length];
snapStream.Seek(0, SeekOrigin.Begin);
snapStream.Read(data, 0, (int)snapStream.Length);

Or you can use the function ToArray() that always copies from the start:

byte[] data = snapStream.ToArray();
ZephyrDogma commented 14 hours ago

It seems to have worked, thanks a lot!

ZephyrDogma commented 14 hours ago

Btw is it possible to instead of getting the frame by snapshot to obtain the frames i want from Recorder_OnFrameRecorded event?

ZephyrDogma commented 13 hours ago

It seems as when i do recorder.Record(stream); into a stream with the following settings, when i check the stream it comes with lenght = 0.

RecorderOptions options = new RecorderOptions
            {
                SourceOptions = new SourceOptions
                {
                    //Populate and pass a list of recordingsources.
                    RecordingSources = sources
                },
                OutputOptions = new OutputOptions
                {
                    RecorderMode = RecorderMode.Screenshot,
                    //This sets a custom size of the video output, in pixels.
                    OutputFrameSize = new ScreenSize(1920, 1080),
                    //Stretch controls how the resizing is done, if the new aspect ratio differs.
                    Stretch = StretchMode.Uniform
                },
                AudioOptions = new AudioOptions
                {
                    Bitrate = AudioBitrate.bitrate_128kbps,
                    Channels = AudioChannels.Stereo,
                    IsAudioEnabled = true,
                },
                VideoEncoderOptions = new VideoEncoderOptions
                {
                    Bitrate = 8000 * 1000,
                    Framerate = 60,
                    IsFixedFramerate = true,
                    //Currently supported are H264VideoEncoder and H265VideoEncoder
                    Encoder = new H264VideoEncoder
                    {
                        BitrateMode = H264BitrateControlMode.CBR,
                        EncoderProfile = H264Profile.Main,
                    },
                    //Fragmented Mp4 allows playback to start at arbitrary positions inside a video stream,
                    //instead of requiring to read the headers at the start of the stream.
                    IsFragmentedMp4Enabled = true,
                    //If throttling is disabled, out of memory exceptions may eventually crash the program,
                    //depending on encoder settings and system specifications.
                    IsThrottlingDisabled = false,
                    //Hardware encoding is enabled by default.
                    IsHardwareEncodingEnabled = true,
                    //Low latency mode provides faster encoding, but can reduce quality.
                    IsLowLatencyEnabled = false,
                    //Fast start writes the mp4 header at the beginning of the file, to facilitate streaming.
                    IsMp4FastStartEnabled = false

                },
                MouseOptions = new MouseOptions
                {
                    //Displays a colored dot under the mouse cursor when the left mouse button is pressed.  
                    IsMouseClicksDetected = false,
                    MouseLeftClickDetectionColor = "#FFFF00",
                    MouseRightClickDetectionColor = "#FFFF00",
                    MouseClickDetectionRadius = 30,
                    MouseClickDetectionDuration = 100,
                    IsMousePointerEnabled = true,
                    /* Polling checks every millisecond if a mouse button is pressed.
                       Hook is more accurate, but may affect mouse performance as every mouse update must be processed.*/
                    MouseClickDetectionMode = MouseDetectionMode.Hook
                },
                OverlayOptions = new OverLayOptions
                {
                    //Populate and pass a list of recording overlays.
                    Overlays = new List<RecordingOverlayBase>()
                },
                SnapshotOptions = new SnapshotOptions
                {
                    //Take a snapshot of the video output at the given interval
                    SnapshotsWithVideo = false,
                    SnapshotsIntervalMillis = 1000,
                    SnapshotFormat = ImageFormat.JPEG,
                    //Optional path to the directory to store snapshots in
                    //If not configured, snapshots are stored in the same folder as video output.
                    SnapshotsDirectory = destinationPath
                },
                LogOptions = new LogOptions
                {
                    //This enabled logging in release builds.
                    IsLogEnabled = false,
                    //If this path is configured, logs are redirected to this file.
                    LogFilePath = "recorder.log",
                    LogSeverityLevel = ScreenRecorderLib.LogLevel.Debug
                }
            };
sskodje commented 9 hours ago

It's most likely an async issue or the stream goes out of scope. Check https://github.com/sskodje/ScreenRecorderLib/blob/d4e6dc3327072595267c33587d063527622bfbe3/Tests/ScreenRecorderTests.cs#L266

sskodje commented 7 hours ago

Functionality for getting source and output preview is now added in release 6.3.0