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