Skip to content

feat(camera): Jolla Camera UI on Marathon's lifecycle - #54

Draft
patrickjquinn wants to merge 6 commits into
feat/q25-front-camerafrom
feat/camera-jolla-ui
Draft

patrickjquinn wants to merge 6 commits into
feat/q25-front-camerafrom
feat/camera-jolla-ui

Conversation

@patrickjquinn

Copy link
Copy Markdown
Owner

Stacked on #53. Replaces the Camera app's basic page with the Jolla Camera's controls, taken from Shipwright's port, on Marathon's lifecycle.

UI

  • From Jolla (BSD-3-Clause, only those files; apps/camera/LICENSE.BSD-3-Clause installed with the app): the shutter, the photo/video menu, the front/back switch, the pull-down settings panel (timer, grid; flash, exposure modes and white balance where a camera has them), the button layout editor, the recording timer, the swipe-across camera roll and the cover. Shipwright's proprietary files are not included.
  • Marathon's own (Apache-2.0): Camera, CameraConfigs, CameraRecorder, CameraImageProcessing, VideoOutput, SettingsBase and CaptureModel give that QML the Qt 5 Multimedia API it expects, over CameraController; the roll's delete/share/Open Gallery controls and video playback.
  • Controls the camera can't honour are not offered: the exposure slider is hidden (the software ISP ignores ExposureValue) and focus is fixed.
  • The Jolla icon-camera-* names map to Phosphor glyphs.

Lifecycle

  • Activity follows the shell's applicationActive; the camera waits for the first frame.
  • Back closes the settings panel, then the roll, then leaves the app.
  • A recording holds a recording background task.
  • camera.open and camera.capture still answer.

CameraController

  • Lists cameras with a stable id, side and mounting rotation (from the sensor's device tree node where Qt has none), sets the viewfinder format, turns photos upright, and writes photos whole before they appear in the roll.
  • Restarts the camera for a format change, since libcamerasrc can't renegotiate, and restarts a camera that is active but sends no frames.
  • Viewfinder frames are converted off the GUI thread: about 80% of a core down to 7% on the Q25.
  • Captures can delete any capture.

libcamera r2 (patch 0008): libcamerasrc never disconnected requestCompleted when it closed the camera, so any in-process restart (background/return, roll and back, camera or format switch) crashed the app.

Also: generate.py no longer stops at hand-drawn glyphs, and Reef's package page icons are mapped (Lint_IconMap was failing).

Tested on the Zinwa Q25 (front IMX111, back S5KJN1): photos and H.264 video from both cameras, photo/video and camera switches, the settings panel, deleting from the roll, back from the roll, leaving and returning (one process throughout), camera.open/camera.capture over D-Bus, the cover.

Known gaps

  • Videos are saved unrotated: Qt 6.11's GStreamer recorder crashes on an orientation tag.
  • Recording in the background drops to about 2 fps.
  • Photos are at viewfinder size, not full resolution.

generate.py stopped with a KeyError at star-fill, which was drawn by
hand because Phosphor Thin has no filled star, so no edit to icon-map.txt
could be regenerated. It now leaves glyphs outside Phosphor's table as
they are.
certificates, chat, sd-card, secure and sounds had no glyph, so they
drew nothing and Lint_IconMap failed. Phosphor has no SD card; a hard
drive stands in for storage.
libcamerasrc connected the camera's requestCompleted signal when it
opened the camera and never disconnected it. The camera outlives the
element, so a camera app that stops and starts its camera crashed on
the first restart: reopened, every request completed twice (an
assertion in GstLibcameraSrcState::requestCompleted); recreated, the
freed element was called.

Patch 0008 disconnects it on close; libcamera r2. With it the Q25's
Camera app keeps streaming through gallery, background, camera-switch
and photo/video restarts.
Every frame went through QVideoFrame::toImage(), which converts through
the GPU, and then convertToFormat(), both on the GUI thread. At 30 fps
that kept the Q25's GUI thread busy enough that the camera app
sometimes drew nothing at all.

Frames are converted on the thread that delivers them, and RGB frames
are copied from the mapped buffer as they are; only the repaint is
queued to the GUI thread. With the camera running the GUI thread went
from about 80% to 7% of a core.
The camera app's controls come from the Jolla Camera and ask for
Sailfish's icon-camera-* names: flash, timer, grid, capture mode,
switch, reset, the video shutter, and the modes and white balances it
shows when a camera offers them. Each maps to a Phosphor glyph, at the
size Sailfish draws it. imaging and qr are the high-resolution and QR
switches' icons.
The Camera app takes Shipwright's Jolla Camera controls in place of its
own basic page: the shutter, the photo and video menu, the front and
back switch, the settings panel pulled down from the top (timer, grid,
and flash, exposure modes and white balance where the camera has them),
the button layout editor, the recording pill and the camera roll beside
the viewfinder, with the Jolla cover. Those QML files are the Jolla
Camera's, BSD-3-Clause (LICENSE.BSD-3-Clause, installed with the app),
with Shipwright's Qt 6 and Keel changes and without its own features.

Marathon supplies the rest:

- Camera, CameraRecorder, CameraImageProcessing, CameraConfigs and
  VideoOutput give that QML the Qt 5 Multimedia API it is written
  against, over CameraController. A control the camera lacks is not
  offered: exposure compensation is hidden (the software ISP ignores
  ExposureValue), and focus is fixed.
- SettingsBase and CaptureModel put captures where Captures does
  (~/Pictures/Marathon); the roll is that folder, and Captures can now
  delete any capture, not just the latest.
- The roll's controls (delete, share, open Gallery) and its video
  playback are Marathon's own.
- CameraApp keeps Marathon's lifecycle: activity follows the shell's
  applicationActive, back closes the settings panel, then the roll,
  then leaves the app, the camera waits for the first frame, a
  recording holds a "recording" background task, and camera.open and
  camera.capture still answer.

CameraController lists each camera with a stable id, its side and its
mounting rotation (from the sensor's device tree node where Qt has
none), sets the viewfinder format, restarts the camera for a format
change (libcamerasrc cannot renegotiate), turns photos upright and
writes them whole before they show in the roll, and restarts a camera
that is active but sends no frames. Videos stay as the sensor delivers
them: Qt 6.11's GStreamer recorder crashes on an orientation tag.

Tested on the Zinwa Q25 (front IMX111, back S5KJN1): photos and H.264
video from both cameras, photo and video switches, the camera switch,
the settings panel, the roll (delete, back to the viewfinder), back
from the roll and leaving and returning to the app with one process
throughout, camera.open and camera.capture over D-Bus, and the cover.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant