QuantumEntangledAndy / neolink

An RTSP bridge to Reolink IP cameras
GNU Affero General Public License v3.0
354 stars 49 forks source link

Capture single frame #8

Closed entropin closed 1 year ago

entropin commented 3 years ago

Not sure if this makes sense for anyone else than me, but ill add it here anyhow, sine i use it in my branch and it seams harmless :)

QuantumEntangledAndy commented 3 years ago

Cool, looks useful so I will probably merge some form of it when I get time thanks

entropin commented 3 years ago

Also as a rational, most Reolink cameras do have a cgi-bin url to call to create a snap, the E1 and E1 Pro dose not, this can be used for a snapshot subcomand as well

QuantumEntangledAndy commented 3 years ago

I imagine that most use cases though such as a rtsp/onvif preview are pulling from the stream already and will just copy the next iframe, especially since you can't pull from the same connection twice.

entropin commented 3 years ago

Oki, so I added this "init_stream" toggle to my code in the PR for allowing the possibility of subscribing to frame capture first and than start the video stream later. or the reverse.

When trying to validate that this actually worked, I got into my first real big fight with the borrow checker....

I thought i caould just spawn a quick thread to test it out, so i added this to the rtps mod:

neolink\src\rtsp\mod.rs line 255

         .........  
        info!(
            "{}: Starting video stream {}",
            camera_config.name, stream_name
        );

        let arc_cam = Arc::new(camera);

        let sender = thread::spawn(move || {
            let cam = &*arc_cam;
            cam.capture_frame("mainStream", false);
        });

        arc_cam.start_video(outputs, stream_name).with_context(|| format!("Error while streaming {}", camera_config.name))

Am deep into research of Arc, Mutex and lifetimes so i don't need a deep explanation, i'll figure it out, but am wondering if what am trying to do is even possible. I have written like 50 variation of the code above, added 'static on 200 places and am starting to feel insane :D Is there a quick fix to this made up problem?

QuantumEntangledAndy commented 3 years ago

So arcs are about making sharable reference counted handles on something.

You make another copy with .clone

Have you tried:

let arc_cam = Arc::new(camera);
let cap_arc_cam = arc_cam.clone();
let sender = thread::spawn(move || {
    cap_arc_cam.capture_frame("mainStream", false);
});

arc_cam.start_video(outputs, stream_name).with_context(|| format!("Error while streaming {}", camera_config.name))
QuantumEntangledAndy commented 3 years ago

It doesn't actually clone the underlying data just the increments the reference count.

Arc only works as read-only references & never &mut

So if you want &mut you have to combine it with something like a Mutex which can lock an object to ensure that you are the sole user and therefore grant mutability. In this case though we don't need the mutability. So just Arc is fine.

QuantumEntangledAndy commented 3 years ago

You will run into another issue though because you can only subscribe to a msg id once.

And both your codes are trying to pull from msg id 3.

entropin commented 3 years ago

Thanks! Ah I have to look into the subscription code, not use if I'll need that on the Rust version so I'll just remove the toggle but later on you might see a PR for multiple receivers.

I have that in my c# client and it is handy in some cases.

QuantumEntangledAndy commented 3 years ago

Well I have an idea that will let us subscribe on the msg number rather then the message ID which will allow for this. But it will probably cause other issues if you try and request a HD stream twice.

It might be possible to just use a bus so that we can have one broadcaster and multiple consumers of the data

entropin commented 3 years ago

Hehe, so I have spent 6h now and am just about ready to give up on Rust :p Turn out my brain really needs static hashMaps or dicts when dealing with events.

Anyhow, it seams to me that I have to use a crossbeam or the like. So will try to play with that tomorrow :D

QuantumEntangledAndy commented 3 years ago

Neolink already links against crossbeam_channel so yeah use it if you need it. If you want any specific help with something your welcome to post some code for discussion

entropin commented 3 years ago

Cool, I see that we use crossbeam in the RTSP mod, but I can't really understand why. Since we are using an arc_cam cant we just spawn "normal" threads? What magic powers does crossbeam give us? other than its awsome that's its inclouded since i need it :D

QuantumEntangledAndy commented 3 years ago

crossbeam also ensures rather nicely that all the threads close at the end of crossbeam::scope although we could have done this with a std join instead.