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

is their a way to get encoded videochunks in realtime, all in memory? #265

Closed JanssonTheBest closed 11 months ago

JanssonTheBest commented 11 months ago

While recording

sskodje commented 11 months ago

If you create a custom stream that derives from Stream , you can use it as a destination and you should get the data in the Write function to do what you wish with.

JanssonTheBest commented 11 months ago

If you create a custom stream that derives from Stream , you can use it as a destination and you should get the data in the Write function to do what you wish with.

But it wont be encoded then?

sskodje commented 11 months ago

It's encoded in h264 or HEVC depending on settings. Providing a stream or file path doesn't matter, internally it writes to the stream anyway. The file path option is just convenience.

JanssonTheBest commented 11 months ago

It's encoded in h264 or HEVC depending on settings. Providing a stream or file path doesn't matter, internally it writes to the stream anyway. The file path option is just convenience.

Wait how is the library able to encode the recording in realtime? Isnt that a quite specific thing, but I guess its my lucky day

sskodje commented 11 months ago

You must enable fragmented mp4 for it to work. It should produce data within a couple hundred milliseconds, so it's not zero latency, it's just the way the encoder works. Enabling low latency might improve the latency, but i'm not sure. It's not something i've used myself, but you should be able to for example send the bytes over a network.

JanssonTheBest commented 11 months ago

You must enable fragmented mp4 for it to work. It should produce data within a couple hundred milliseconds, so it's not zero latency, it's just the way the encoder works. Enabling low latency might improve the latency, but i'm not sure. It's not something i've used myself, but you should be able to for example send the bytes over a network.

Oh nice! How could I make the video not save to the disk after recording :)

JanssonTheBest commented 11 months ago

You must enable fragmented mp4 for it to work. It should produce data within a couple hundred milliseconds, so it's not zero latency, it's just the way the encoder works. Enabling low latency might improve the latency, but i'm not sure. It's not something i've used myself, but you should be able to for example send the bytes over a network.

Is the library writing to the buffer or how does it work? Because for me it doesn't write to it.

sskodje commented 11 months ago

You need to mark your stream as seekable and readable, even though it's not. When using Fragmented MP4 it doesn't seek, it just writes to it start to finish. Something like this:

    public class CustomStream : Stream
    {

        public override bool CanRead => true;

        public override bool CanSeek => true;

        public override bool CanWrite => true;

        public override long Length { get; } = 0;

        public override long Position { get; set; } = 0;

        public override void Flush()
        {
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            return 0;
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return 0;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            Debug.WriteLine(DateTime.Now.ToString("HH::mm:ss:fff") + " Wrote " + count + " bytes to stream");
        }

        public override void SetLength(long value)
        {

        }
    }
            var opts = new RecorderOptions
            {
                VideoEncoderOptions = new VideoEncoderOptions
                {
                    IsLowLatencyEnabled = true,
                    IsFragmentedMp4Enabled = true
                }
            };

            Recorder rec = Recorder.CreateRecorder(opts);
            rec.Record(myStream);
JanssonTheBest commented 11 months ago

You need to mark your stream as seekable and readable, even though it's not. When using Fragmented MP4 it doesn't seek, it just writes to it start to finish. Something like this:

    public class CustomStream : Stream
    {

        public override bool CanRead => true;

        public override bool CanSeek => true;

        public override bool CanWrite => true;

        public override long Length { get; } = 0;

        public override long Position { get; set; } = 0;

        public override void Flush()
        {
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            return 0;
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return 0;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            Debug.WriteLine(DateTime.Now.ToString("HH::mm:ss:fff") + " Wrote " + count + " bytes to stream");
        }

        public override void SetLength(long value)
        {

        }
    }
            var opts = new RecorderOptions
            {
                VideoEncoderOptions = new VideoEncoderOptions
                {
                    IsLowLatencyEnabled = true,
                    IsFragmentedMp4Enabled = true
                }
            };

            Recorder rec = Recorder.CreateRecorder(opts);
            rec.Record(myStream);

Every time it writes to the stream will it be a video chunk that isn't raw and can be read using a videoframe reader? Or how do I get the fragmentedmp4 in realtime.

JanssonTheBest commented 11 months ago

It seems like the header for each fragment is being written in separate method call, but Im trying to get the fragment in the write method.

sskodje commented 11 months ago

The data you get in the stream is the exact same data that would be written to a file. Headers and all. If you need to parse the headers etc, you will need to do it yourself.

JanssonTheBest commented 11 months ago

The data you get in the stream is the exact same data that would be written to a file. Headers and all. If you need to parse the headers etc, you will need to do it yourself.

First it seems like there is a long header using 5 write method calls then the fragments come with their headers. Which uses 2 method calls, then the third will be the actual data of each fragment. Im new to this, could you explain each header?

sskodje commented 11 months ago

I'm sorry, It's a bit outside the scope of this library. They should be well documented though. ChatGPT can probably be helpful in explaining them or even making a parser.

JanssonTheBest commented 11 months ago

I'm sorry, It's a bit outside the scope of this library. They should be well documented though. ChatGPT can probably be helpful in explaining them or even making a parser.

Yeah you're right, "ajgamerpro" on discord though at anytime, if you feel free to help.