[libcamera-devel] Issue allocating many frame buffers on RasPi
Jacopo Mondi
jacopo at jmondi.org
Mon Jul 4 10:31:17 CEST 2022
Hi Alan,
On Sat, Jul 02, 2022 at 07:48:48AM -0400, Alan W Szlosek Jr via libcamera-devel wrote:
> Hi libcamera, I'm creating a security camera app for RasPis and I'm
> having trouble allocating 20 frame buffers (would like to alloc even
> more). Do you know why? Do you have suggestions? I'm currently testing
> on a Raspberry Pi 3B+.
>
Can I ask why you need to allocate tham many buffers in the video
device ?
> This is the output I'm getting. The return value from allocate() seems
> to imply that everything is fine ("Allocated 20 buffers for stream")
> when it's not fine behind the scenes.
>
> [1:23:50.594602178] [1217] INFO Camera camera_manager.cpp:293
> libcamera v0.0.0+3544-22656360
> [1:23:50.657034054] [1218] WARN RPI raspberrypi.cpp:1241 Mismatch
> between Unicam and CamHelper for embedded data usage!
> [1:23:50.659149325] [1218] INFO RPI raspberrypi.cpp:1356 Registered
> camera /base/soc/i2c0mux/i2c at 1/imx219 at 10 to Unicam device /dev/media3
> and ISP device /dev/media0
> [1:23:50.660510009] [1217] INFO Camera camera.cpp:1029 configuring
> streams: (0) 1640x922-YUV420
> [1:23:50.661246471] [1218] INFO RPI raspberrypi.cpp:760 Sensor:
> /base/soc/i2c0mux/i2c at 1/imx219 at 10 - Selected sensor format:
> 1920x1080-SBGGR10_1X10 - Selected unicam format: 1920x1080-pBAA
> Allocated 20 buffers for stream
> [1:23:50.733980221] [1218] ERROR V4L2 v4l2_videodevice.cpp:1218
> /dev/video14[14:cap]: Not enough buffers provided by V4L2VideoDevice
> [1:23:50.734467203] [1218] ERROR RPI raspberrypi.cpp:1008 Failed to
> allocate buffers
This seems to happen when the pipeline starts and tries to allocate
buffers for its internal usage. Might it be you simply run out of
available memory ?
Is there anything on your dmesg output that might suggest that, like a
message from your CMA allocator ?
Can you try with allocating an increasing number of buffers until you
don't get to the failure limit ?
> [1:23:50.739962387] [1217] ERROR Camera camera.cpp:528 Camera in
> Configured state trying queueRequest() requiring state Running
> [1:23:50.740078898] [1217] ERROR Camera camera.cpp:528 Camera in
> Configured state trying queueRequest() requiring state Running
>
> Here's how I'm compiling:
>
> clang++ -g -std=c++17 -o scaffold \
> -I /usr/include/libcamera \
> -L /usr/lib/aarch64-linux-gnu \
> -l camera -l camera-base \
> scaffold.cpp
>
> And here's the code I'm using. Thank you!
>
> #include <iomanip>
> #include <iostream>
> #include <memory>
> #include <thread>
>
> #include <libcamera/libcamera.h>
>
> using namespace libcamera;
>
> static std::shared_ptr<Camera> camera;
>
> time_t previousSeconds = 0;
> int frames = 0;
> static void requestComplete(Request *request)
> {
> std::unique_ptr<Request> request2;
> if (request->status() == Request::RequestCancelled)
> return;
> const std::map<const Stream *, FrameBuffer *> &buffers = request->buffers();
>
> request->reuse(Request::ReuseBuffers);
> camera->queueRequest(request);
>
> struct timespec delta;
> clock_gettime(CLOCK_REALTIME, &delta);
> if (previousSeconds == delta.tv_sec) {
> frames++;
> } else {
> fprintf(stdout, "Frames: %d\n", frames);
> frames = 1;
> previousSeconds = delta.tv_sec;
> }
> }
>
> int main()
> {
> std::unique_ptr<CameraManager> cm = std::make_unique<CameraManager>();
> cm->start();
>
> if (cm->cameras().empty()) {
> std::cout << "No cameras were identified on the system."
> << std::endl;
> cm->stop();
> return EXIT_FAILURE;
> }
>
> std::string cameraId = cm->cameras()[0]->id();
> camera = cm->get(cameraId);
>
> camera->acquire();
>
> // VideoRecording
> std::unique_ptr<CameraConfiguration> config =
> camera->generateConfiguration( { StreamRole::VideoRecording } );
> StreamConfiguration &streamConfig = config->at(0);
> streamConfig.size.width = 1640; //640;
> streamConfig.size.height = 922; //480;
> // This seems to default to 4, but we want to queue buffers for post
> // processing, so we need to raise it.
> // 10 works ... oddly, but 20 fails behind the scenes. doesn't apear
> // to be an error we can catch
> streamConfig.bufferCount = 20;
>
> // TODO: check return value of this
> CameraConfiguration::Status status = config->validate();
> if (status == CameraConfiguration::Invalid) {
> fprintf(stderr, "Camera Configuration is invalid\n");
> } else if (status == CameraConfiguration::Adjusted) {
> fprintf(stderr, "Camera Configuration was invalid and has been
> adjusted\n");
> }
>
> camera->configure(config.get());
>
> FrameBufferAllocator *allocator = new FrameBufferAllocator(camera);
>
> for (StreamConfiguration &cfg : *config) {
> // TODO: it's possible we'll need our own allocator for raspi,
> // so we can enqueue many frames for processing
> int ret = allocator->allocate(cfg.stream());
> // This error handling doesn't catch a failure to allocate 20 buffers
> if (ret < 0) {
> std::cerr << "Can't allocate buffers" << std::endl;
> return -ENOMEM;
> }
>
> size_t allocated = allocator->buffers(cfg.stream()).size();
> std::cout << "Allocated " << allocated << " buffers for
> stream" << std::endl;
> }
>
>
> Stream *stream = streamConfig.stream();
> const std::vector<std::unique_ptr<FrameBuffer>> &buffers =
> allocator->buffers(stream);
> std::vector<std::unique_ptr<Request>> requests;
>
> for (unsigned int i = 0; i < buffers.size(); ++i) {
> std::unique_ptr<Request> request = camera->createRequest();
> if (!request)
> {
> std::cerr << "Can't create request" << std::endl;
> return -ENOMEM;
> }
>
> const std::unique_ptr<FrameBuffer> &buffer = buffers[i];
> int ret = request->addBuffer(stream, buffer.get());
> if (ret < 0)
> {
> std::cerr << "Can't set buffer for request"
> << std::endl;
> return ret;
> }
>
> requests.push_back(std::move(request));
> }
>
> camera->requestCompleted.connect(requestComplete);
>
> // sets fps (via frame duration limts)
> // TODO: create ControlList and move to global var
> // TODO: is there a raspi-specific implementation of this?
> libcamera::ControlList controls(libcamera::controls::controls);
> int framerate = 30;
> int64_t frame_time = 1000000 / framerate; // in microseconds
> controls.set(libcamera::controls::FrameDurationLimits, {
> frame_time, frame_time });
>
> camera->start(&controls);
> for (auto &request : requests)
> camera->queueRequest(request.get());
>
> //60 * 60 * 24 * 7; // days
> int duration = 10;
>
> for (int i = 0; i < duration; i++) {
> std::cout << "Sleeping" << std::endl;
> std::this_thread::sleep_for(std::chrono::milliseconds(1000));
> }
>
>
> return 0;
> }
>
> --
> Alan Szlosek
More information about the libcamera-devel
mailing list