Search code examples
c++cameraraspberry-pi3mmap

mmap failed on libcamera returned frame data


I'm working with camera on a Raspberry Pi 3B. The frame data returned by libcamera is given by tuples of raw fd, size and offset. And according to the official document I have to mmap them to access frame data. However, sometimes the code piece below fail to execute mmap (usually occurs after one or two times of successful operations).

void copy_plane_to_texture(const libcamera::FrameBuffer::Plane &plane, int w, int h, GLuint texture)
{
    glBindTexture(GL_TEXTURE_2D, texture);
    auto *addr = (unsigned char *)mmap(nullptr, plane.length, PROT_READ, MAP_PRIVATE, plane.fd.get(), plane.offset);
    if (addr == MAP_FAILED)
    {
        clog << "mmap failed for plane fd " << plane.fd.get() << " size " << plane.length << " offset " << plane.offset << ": " << strerror(errno) << endl;
        abort();
    }
    clog << "plane fd " << plane.fd.get() << " size " << plane.length << " offset " << plane.offset << " mapped to address " << std::hex << size_t(addr) << std::dec << endl;
    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, addr);
    glFinish(); // wait until copying is really finished
    if (munmap(addr, plane.length) != 0)
    {
        clog << "munmap failed on address " << std::hex << size_t(addr) << ": " << strerror(errno) << endl;
        abort();
    }
}

A typical output log of this part:

plane fd 18 size 921600 offset 0 mapped to address 6b51e000
plane fd 18 size 230400 offset 921600 mapped to address 6b5c6000
mmap failed for plane fd 18 size 230400 offset 1152000: Invalid argument

According to man 2 mmap, it only raise EINVAL on three circumstances:

  • We don't like addr, length, or offset (e.g., they are too large, or not aligned on a page boundary).
  • (since Linux 2.6.12) length was 0.
  • flags contained neither MAP_PRIVATE or MAP_SHARED, or contained both of these values.

It is obvious I have non-zero length and has specified correct flag, so the remaining possibility is invalid length/offset. However the length/offset is given by libcamera so I have no choice on it. How could I solve this error?


Solution

  • Somebody on another forum answered me. The color planes in one frame buffer is using the same dma file descriptor, and I should mmap them in one time instead of three. Otherwise the offsets of latter planes are not aligned to page boundaries and mmap will not happy.