lit-robotics / libcamera-rs

Experimental Rust bindings for libcamera
Apache License 2.0
46 stars 15 forks source link

Changing FrameSize #23

Closed Sc0rpe closed 1 year ago

Sc0rpe commented 1 year ago

Hi, i am currently developing a camera server with your library. Therefore i am running the Frame aquisition in a loop. In this loop i am receiving messages via MPSC. When i receive such a message i want to change the video frame size. For my trials i had rebuild your video_capture example. After i change video size i tried to rebuild the framebuffers and create new request with them. However when it executes the allocation let mut framebuff = alloc.alloc(&stream).unwrap(); of the new framebuffers i get an error [0:22:47.613844067] [1719] ERROR V4L2 v4l2_videodevice.cpp:1352 /dev/video14[13:cap]: Buffers already allocated

My code looks like this

let mut cfgs = actcam.generate_configuration(&[StreamRole::Raw]).unwrap();
cfgs.get_mut(0).unwrap().set_size(Size{width: new_width, height: new_height});
cfgs.validate();
actcam.configure(&mut cfgs).expect("Unable to configure camera");

// Allocate frame buffers for the stream
let cfg = cfgs.get(0).unwrap();
let mut stream = cfg.stream().unwrap();
let mut framebuff = alloc.alloc(&stream).unwrap(); // this gives me error "buffers already allocated" from V4L2
...
//creating request with the new buffer

I guess i have to free or drop the old framebuffers somehow. Is there a function for that? I couldn't find anything that suits my needs. Also for the requests. As in the video_capture example i do like

// Recycle the request back to the camera for execution                   
req.reuse(ReuseFlag::REUSE_BUFFERS);
actcam.queue_request(req).unwrap();   

after changing the video size i guess i have to remove the old requests and just queue the new ones. Is there anything i can do to clean the request list and remove the old requests?

chemicstry commented 1 year ago

Hi,

It could be that some deallocation methods are missing in the rust bindings. Do you know any C/C++ libcamera example that does size reconfiguration while running? It would help debugging knowing what is the correct sequence of calls.

Sc0rpe commented 1 year ago

Unfortunately i couldn't find anything about resizing the video while running.

chemicstry commented 1 year ago

I tested this by taking video_capture example and duplicating everything after cam.acquire(). The only thing needed was to call cam.stop() in between two blocks. See here: https://gist.github.com/chemicstry/2326de3367c010445806a53b8e4ef284

I think your problem was that you did not drop FrameBufferAllocator, which resulted in the same error for me.

I created a PR to fix that, please try if it helps: https://github.com/lit-robotics/libcamera-rs/pull/24

Sc0rpe commented 1 year ago

Thanks to your hints i could manage to resize the video while running! It seems it is necessary to drop and create a new CameraConfiguration (i reused the existing one, just set a new size) to get it working. let mut cfgs = cam.generate_configuration(&[StreamRole::VideoRecording]).unwrap(); Without this line in advance to buil the new buffers, it didn't worked for me! However i still have the problem to clean the request queue for the camera. In your example you don't have this problem because you let the loop finish, then starting a new one. After resizing, but before queuing the newly created requests, i do as following:

  let b = cfgs.get_mut(0).unwrap().get_buffer_count(); // getting number of buffers used
  for i in 1..b {
      if let Ok(req) = rx.recv_timeout(Duration::from_secs(2)) {};
      thread::sleep(Duration::from_micros(1)); // not sure if i need it
  }
  ...
  // queuing new request

Do you think this is an appropriate solution or might this fail or cause problems in another way?

So far, thank you very much for your help!!!

chemicstry commented 1 year ago

When you call ActiveCamera::stop() it will immediately complete all queued requests with RequestStatus::Cancelled. libcamera docs say that all requests are completed synchronously when calling stop(), so you should be able to just do this:

cam.stop().unwrap();
while let Ok(_) = rx.try_recv() {}
Sc0rpe commented 1 year ago

Thanks for the information. Works like a charm! This issue is solved for me. Thank you very much for your help!