Browse Source

qr-code-scanner: Use is_camera_present() and allow multiple starts

This now uses `is_camera_present()` to check whether we have a camera.
It also makes sure that a pipeline is closed before a new one is
started.
merge-requests/1327/merge
Julian Sparber 4 years ago
parent
commit
5bb7e52470
  1. 5
      Cargo.lock
  2. 2
      Cargo.toml
  3. 15
      src/contrib/qr_code_scanner/camera_paintable.rs
  4. 80
      src/contrib/qr_code_scanner/mod.rs

5
Cargo.lock generated

@ -4090,11 +4090,10 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.12.0"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc"
checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
dependencies = [
"autocfg",
"bytes",
"libc",
"memchr",

2
Cargo.toml

@ -21,7 +21,7 @@ gtk-macros = "0.3"
once_cell = "1.5"
serde = "1.0.130"
serde_json = "1.0"
tokio = { version = "1.2", features = ["rt", "rt-multi-thread"] }
tokio = { version = "1.15", features = ["rt", "rt-multi-thread", "sync"] }
url = "2.2"
secret-service = "2.0"
html2pango = "0.4"

15
src/contrib/qr_code_scanner/camera_paintable.rs

@ -212,7 +212,6 @@ mod imp {
pub struct CameraPaintable {
pub sink: camera_sink::CameraSink,
pub detector: QrCodeDetector,
pub pipeline: RefCell<Option<gst::Pipeline>>,
pub sender: Sender<Action>,
pub image: RefCell<Option<gdk::Texture>>,
@ -227,7 +226,6 @@ mod imp {
Self {
pipeline: RefCell::default(),
sink: camera_sink::CameraSink::new(sender.clone()),
detector: QrCodeDetector::new(sender.clone()),
image: RefCell::new(None),
sender,
receiver,
@ -337,6 +335,7 @@ impl Default for CameraPaintable {
impl CameraPaintable {
pub fn set_pipewire_fd<F: AsRawFd>(&self, fd: F, node_id: u32) {
self.close_pipeline();
let pipewire_element = gst::ElementFactory::make("pipewiresrc", None).unwrap();
pipewire_element
.set_property("fd", &fd.as_raw_fd())
@ -350,6 +349,7 @@ impl CameraPaintable {
fn init_pipeline(&self, pipewire_src: gst::Element) {
let self_ = imp::CameraPaintable::from_instance(self);
let pipeline = gst::Pipeline::new(None);
let detector = QrCodeDetector::new(self_.sender.clone()).upcast();
let tee = gst::ElementFactory::make("tee", None).unwrap();
let queue = gst::ElementFactory::make("queue", None).unwrap();
@ -377,21 +377,14 @@ impl CameraPaintable {
&tee,
&queue,
&videoconvert1,
self_.detector.upcast_ref(),
&detector,
&queue2,
&videoconvert2,
self_.sink.upcast_ref(),
])
.unwrap();
gst::Element::link_many(&[
&pipewire_src,
&tee,
&queue,
&videoconvert1,
self_.detector.upcast_ref(),
])
.unwrap();
gst::Element::link_many(&[&pipewire_src, &tee, &queue, &videoconvert1, &detector]).unwrap();
tee.link_pads(None, &queue2, None).unwrap();
gst::Element::link_many(&[&queue2, &videoconvert2, self_.sink.upcast_ref()]).unwrap();

80
src/contrib/qr_code_scanner/mod.rs

@ -20,6 +20,7 @@ mod imp {
use gtk::CompositeTemplate;
use once_cell::sync::Lazy;
use std::cell::Cell;
use tokio::sync::OnceCell;
use super::*;
@ -29,8 +30,8 @@ mod imp {
pub paintable: CameraPaintable,
#[template_child]
pub picture: TemplateChild<gtk::Picture>,
pub connection: OnceCell<zbus::Connection>,
pub has_camera: Cell<bool>,
pub is_started: Cell<bool>,
}
#[glib::object_subclass]
@ -116,47 +117,51 @@ impl QrCodeScanner {
glib::Object::new(&[]).expect("Failed to create a QrCodeScanner")
}
async fn connection(&self) -> Result<&zbus::Connection, ashpd::Error> {
let priv_ = imp::QrCodeScanner::from_instance(self);
Ok(priv_
.connection
.get_or_try_init(|| zbus::Connection::session())
.await?)
}
pub fn stop(&self) {
let self_ = imp::QrCodeScanner::from_instance(self);
self_.paintable.close_pipeline();
}
async fn start_internal(&self) -> bool {
let self_ = imp::QrCodeScanner::from_instance(self);
if let Ok(Some(stream_fd)) = stream().await {
pub async fn start(&self) -> bool {
let priv_ = imp::QrCodeScanner::from_instance(self);
if let Ok(stream_fd) = self.stream().await {
if let Ok(node_id) = camera::pipewire_node_id(stream_fd).await {
self_.paintable.set_pipewire_fd(stream_fd, node_id);
self_.has_camera.set(true);
self.notify("has-camera");
priv_.paintable.set_pipewire_fd(stream_fd, node_id);
self.set_has_camera(true);
return true;
}
}
self_.has_camera.set(false);
self.notify("has-camera");
false
self.set_has_camera(false);
return false;
}
pub async fn start(&self) -> bool {
let priv_ = imp::QrCodeScanner::from_instance(self);
let is_started = self.start_internal().await;
priv_.is_started.set(is_started);
is_started
async fn has_camera_internal(&self) -> Result<bool, ashpd::Error> {
let proxy = camera::CameraProxy::new(self.connection().await?).await?;
proxy.is_camera_present().await
}
async fn stream(&self) -> Result<RawFd, ashpd::Error> {
let proxy = camera::CameraProxy::new(self.connection().await?).await?;
proxy.access_camera().await?;
proxy.open_pipe_wire_remote().await
}
fn init_has_camera(&self) {
spawn!(clone!(@weak self as obj => async move {
let priv_ = imp::QrCodeScanner::from_instance(&obj);
let has_camera = if obj.start_internal().await {
if !priv_.is_started.get() {
obj.stop();
}
true
} else {
false
};
priv_.has_camera.set(has_camera);
obj.notify("has-camera");
obj.set_has_camera(obj.has_camera_internal().await.unwrap_or_default());
}));
}
@ -165,6 +170,17 @@ impl QrCodeScanner {
priv_.has_camera.get()
}
fn set_has_camera(&self, has_camera: bool) {
let priv_ = imp::QrCodeScanner::from_instance(self);
if has_camera == self.has_camera() {
return;
}
priv_.has_camera.set(has_camera);
self.notify("has-camera");
}
/// Connects the prepared signals to the function f given in input
pub fn connect_code_detected<F: Fn(&Self, QrVerificationData) + 'static>(
&self,
@ -182,18 +198,6 @@ impl QrCodeScanner {
}
}
async fn stream() -> Result<Option<RawFd>, ashpd::Error> {
let connection = zbus::Connection::session().await?;
let proxy = camera::CameraProxy::new(&connection).await?;
if proxy.is_camera_present().await? {
proxy.access_camera().await?;
Ok(Some(proxy.open_pipe_wire_remote().await?))
} else {
Ok(None)
}
}
#[derive(Clone, Debug, PartialEq, glib::GBoxed)]
#[gboxed(type_name = "QrVerificationDataBoxed")]
struct QrVerificationDataBoxed(QrVerificationData);

Loading…
Cancel
Save