#phonecamera #linuxphone #librem5

Librem 5 camera/kernel can do three possible resolutions, ~1024x768 @ ~24fps, ~2048x.. @ ~31 fps and ~4096x.. @ ~15fps. Debayering is actually easier and better quality if we downscale at the same time, and that allows best framerate, so we do that (2048x.. resolution).

ARM has problems with cache coherency w.r.t. DMA, and kernel solution is to simply disable cache on DMAbufs for userspace, which means accessing video data is 10x slower than it should be on the CPU. Which means debayering on GPU is attractive, and that's what we do. (gold.frag). GPU can do more image signal processing functions easily, too, so we do some of that.

Unfortunately, we hit the same uncached memory problem at the GPU output. So we use separate thread to copy. All this unfortunately does not fit on one core, so we need two threads, one controlling GPU debayer on frame n+1, while the other one copies video data from frame n. (heart.c). We save resulting RGBA data to ramdisk. This all costs maybe 80% of one core.

From there, Python scripts can pick them up: ucam.py displaying the viewfinder and mpegize.py handling the video encoding via gstreamer. There's basically 0% cpu left, but I can encode ~1024x.. video. Unfortunately that's without audio and with viewfinder at 1fps. Plus, combination of C + Python is great for prototyping, but may not be that great for performance.

Code is here: https://gitlab.com/tui/tui/-/tree/master/icam?ref_type=heads .

At this point I'd like viewfinder functionality merged into the rest of GPU processing. Ideally, I'd like to have a bitmap with GUI elements, combine it with scaled RGBA data, and rendering it to screen. I know SDL and Gtk, SDL looked like better match, but I could not get SDL and GPU debayering to work in single process (template SDL code is here https://gitlab.com/tui/debayer-gpu/-/blob/master/sdl/main.c?ref_type=heads ).

If you can integrate main.c and heart.c, that would be welcome. If you have example code that combines SDL with processing on GPU, that would be nice, too. If you know someone who can do GPU/SDL, boost would not be bad, I guess.

@datenwolf
@NekoCWD
@dcz
@martijnbraam
Follow

@pavel @datenwolf @dcz @martijnbraam @NekoCWD I played with it over the last days and I already have 526x390 30 FPS encoding with live viewfinder, perfectly synced audio, color correction, lens shading correction, tone mapping, AWB and AE - consuming about 40% CPU. Still needs chromatic shading correction and AF, and I started experimenting with enabling PDAF.

I can also make the sensor output 60 FPS and RAW10. Patches incoming ;) Still only 2 MIPI lanes though, so no 13MP 30FPS yet.

BTW. Recording 30 minutes with screen off ate about 15% of battery, so 3 hours of recording should be possible.

I think both left- and right-masked PDAF pixels are accessible in 1:2 mode with binning disabled, though I haven't done the math yet to be 100% sure. Enabling/disabling it on demand will be somewhat clunky though. I can also read calibration data from OTP, but AFAIK there are no kernel APIs to expose that to userspace :(
source.puri.sm/Librem5/linux/-

Note that the picture is shifted down-left a bit because the driver was misconfiguring the output parameters to include dummy pixels - fixed that too, along with several out-of-range clocks 👻

@dos @datenwolf @dcz @martijnbraam @NekoCWD I hope you played with it in your day job for about 8 hours a day, because otherwise I'll feel kind of bad :-). Thanks!

Do you also get constant clicking from the AF system? I thought it was gone on Mobian, but then it came back.

526x390 is easy, can you do 1052x..? Is it possible to peek at sources somewhere?

Thanks again.

@pavel @datenwolf @dcz @martijnbraam @NekoCWD It's 526x390, but properly binned (each channel's sample consists of 4 raw pixels averaged), which reduces noise. The shader got heavy though, does only ~35 FPS at this res - but there should be room for optimization. I've been more concerned with its correctness than performance so far.

Stats counting on the CPU with NEON is fast enough for full frame with some subsampling.

I'm giving it some finishing touches and will then publish it of course 😁

@pavel @datenwolf @dcz @martijnbraam @NekoCWD I'd expect moving binning to a separate pre-pass to make it faster, we'll see.
Also, my stats are center-weighted. Millipixels annoyed me with its reluctance to overexpose the sky 😄

@dos @pavel @datenwolf @dcz @martijnbraam @NekoCWD I'm an absolute noob in all these but i have a very naive question : how come older android smartphone can do the same thing with bigger resolution on older chip ? If i compare with an old samsung galaxy s3, it did all this very easily. Is there some secret proprietary sauce to it with specialized closed-source firmware ? Or the librem 5 just has an exotic hardware ?

@lord @datenwolf @dcz @martijnbraam @NekoCWD @pavel Specialized hardware. Phones usually don't have to do image processing nor video encoding on CPU or GPU at all, they have hardware ISP and encoders. L5 does not.

On other hardware there's also a matter of whether there's driver and software support for it, so Android may be able to use that, but pmOS - not necessarily.

@dos @datenwolf @dcz @martijnbraam @NekoCWD @pavel Ok so it really is due to some hardware "missing" and not just some closed-source firmware in the case of L5. Good to know :-)

@dos @datenwolf @dcz @martijnbraam @NekoCWD I'm quite curious how the viewfinder integration looks. Even unfinished code would be interesting to look at :-).

@pavel @datenwolf @dcz @martijnbraam @NekoCWD I'm just using waylandsink at this point, but it could be passed anywhere else. That's literally the least interesting part of the thing 😂

@dos @datenwolf @dcz @martijnbraam @NekoCWD If you have something where you can draw / handle controls on top of the viewfinder, or at least around it. I did some hacks in the past with capturing gstreamer window, but they were a) probably X11 specific and b) not really great code. If you have nice solution, I'd like to see one.

@pavel There's plenty of apps that embed GStreamer's output to look at, and you can even skip it completely and simply import the V4L buffer into SDL's GL context and don't create your own one at all. This is just gluing things together at this point.

@dos I'm not really looking for doing anything with gstreamer output. But if you have example of doing debayering and output via SDL, or know where to find it, I'd love to see it.

@pavel Doing it via GStreamer makes buffer queue management easier, but of course it can be done either way. With SDL you get GL context already, so you just do it the way I showed you some time ago. You skip the context creation part and you're done.

@pavel So I was just adding autofocus to my toy code and I wanted to be able to trigger it by tapping on the viewfinder. Just replaced waylandsink with gtkwaylandsink, grabbed its GtkWidget and added it to my GtkWindow and it works 😛

@dos I have feeling that you'll post few more advancements and then you'll disappear, with that code being gone forever. Probably abducted by aliens as that's clearly alien code :-).

Please publish it somewhere.... we don't want another "Fermat's last theorem" situation.

Also, yes, at 512x.. resolution, things are likely easier. I had a lot of fun trying to get gtk/gstreamer working, and while I got it to work _somehow_, I was not really able to understand/debug performance issues.

@pavel Displaying the viewfinder is free with (gl)waylandsink, as the dmabuf gets passed directly to the compositor in a subsurface, so the resolution is not important - it goes straight to the GPU for compositing. It's important for encoding and that's where uncached buffers can bite you, but since my shader is currently too heavy to handle higher res anyway it's not a thing I concern myself with right now.

And the code is basic, it just takes time to get familiar with the problem space 😜

@dos I want to see how you do that magic... to see if it looks reasonable or if I should keep playing with sdl. Note that first thing gstreamer will do is downscale color information. If you do that in shader -- YUY2 -- gstreamer will be faster. But having 512x.. image with perfect color in each pixel is a waste with h264 compression

@pavel Outputting AYUV is trivial and makes encoding slightly faster, but then you lose the viewfinder for free as that's not a format that can be passed to the compositor.

Ideally we would output planar YUV (perhaps with multiple render targets?) as that can be sampled from with recent etnaviv: gitlab.freedesktop.org/mesa/me

For now I'm limiting myself to what's possible on bookworm/crimson though :)

@dos Not sure about performance implications of multiple render targets. (And yes, living with reasonably old distros is always good). I could live with Y-only viewfinder or maybe AYUV viewfinder is not free but "fast enough" :-).
@dos @datenwolf @dcz @martijnbraam @NekoCWD So, this is what I was targetting with my "gstreamer will downscale UV components" comment: GPU is doing heavy computation to make sure you have great color values for each pixel, only for gstreamer to discard it in the next step.

Anyway, I'd love to see the code :-).

@pavel @datenwolf @dcz @martijnbraam @NekoCWD You could encode to YUV444 or even RGB, but lack of lens corrections is much more visible than chroma subsampling:)

@dos @datenwolf @dcz @martijnbraam @NekoCWD Lens corrections -- are we speaking lens shading or geometry corrections?

I am still eager to see your code. I'd like to try to tweak it for 1024x.. resolution, to get good quality videos.

@pavel @datenwolf @dcz @martijnbraam @NekoCWD Both, including chromatic shading. They're not that bad in still photos, but I find them very distracting when in movement.

I've got a song for you, but you'll have to translate it yourself 😁 youtube.com/watch?v=FdIid5IJEd

I'm relying on kernel changes, so I need to put everything in place first. It also took some time for me to get reasonably confident that what I'm doing is correct. I'm pretty much done though, just some cleanups left to do.

@dos @datenwolf @dcz @martijnbraam @NekoCWD Thanks for the song, translation was easy :-).

I guess -- we are not using the vertex processing of the GPU at all, and that geometry distortion sounds like right job for it. Might need to be done per-color...

I did some stalking, and there's a lot of changes on your gitlab -- https://source.puri.sm/sebastian.krzyszkowiak . Is the video enconding code in the millipixels or somwhere else?
@dos @datenwolf @dcz @martijnbraam @NekoCWD Thanks for the song, I now listened to it again. But I'm still impatient :-).

I see your kernel changes and millipixels changes on puri.sm, but I don't believe that's where the video recording code is..?
Sign in to participate in the conversation
Librem Social

Librem Social is an opt-in public network. Messages are shared under Creative Commons BY-SA 4.0 license terms. Policy.

Stay safe. Please abide by our code of conduct.

(Source code)

image/svg+xml Librem Chat image/svg+xml