mirror of
https://github.com/BetterCorp/BetterFrame.git
synced 2026-05-26 22:26:33 +00:00
fix: resolve all Rust compile errors in kiosk app
This commit is contained in:
parent
e3bb5ae048
commit
c4315917d8
5 changed files with 39 additions and 35 deletions
|
|
@ -27,4 +27,5 @@ tokio = { version = "1", features = ["rt-multi-thread", "macros", "time", "fs"]
|
||||||
# Misc
|
# Misc
|
||||||
dirs = "6"
|
dirs = "6"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
hostname = "0.4"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ mod bundle;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
|
use gtk4::prelude::ApplicationExtManual;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use gstreamer::{self as gst, Element, Pipeline};
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
|
|
||||||
/// Create a GStreamer pipeline for an RTSP camera that outputs to a GTK4 paintable sink.
|
/// Create a GStreamer pipeline for an RTSP camera that outputs to a GTK4 paintable sink.
|
||||||
/// Returns (pipeline, paintable_sink) — the sink's "paintable" property drives a gtk4::Picture.
|
/// Returns (pipeline, paintable_sink).
|
||||||
pub fn create_camera_pipeline(name: &str, rtsp_uri: &str) -> Option<(Pipeline, Element)> {
|
pub fn create_camera_pipeline(name: &str, rtsp_uri: &str) -> Option<(Pipeline, Element)> {
|
||||||
let pipeline_name = format!("cam-{name}");
|
let pipeline_name = format!("cam-{name}");
|
||||||
let pipeline = Pipeline::with_name(&pipeline_name);
|
let pipeline = Pipeline::with_name(&pipeline_name);
|
||||||
|
|
@ -15,13 +15,7 @@ pub fn create_camera_pipeline(name: &str, rtsp_uri: &str) -> Option<(Pipeline, E
|
||||||
.build()
|
.build()
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
let depay_h264 = gst::ElementFactory::make("rtph264depay").build().ok();
|
let decode = gst::ElementFactory::make("decodebin").build().ok()?;
|
||||||
let depay_h265 = gst::ElementFactory::make("rtph265depay").build().ok();
|
|
||||||
let parse_h264 = gst::ElementFactory::make("h264parse").build().ok();
|
|
||||||
let parse_h265 = gst::ElementFactory::make("h265parse").build().ok();
|
|
||||||
let decode = gst::ElementFactory::make("avdec_h264").build()
|
|
||||||
.or_else(|| gst::ElementFactory::make("decodebin").build().ok());
|
|
||||||
|
|
||||||
let convert = gst::ElementFactory::make("videoconvert").build().ok()?;
|
let convert = gst::ElementFactory::make("videoconvert").build().ok()?;
|
||||||
|
|
||||||
let sink = gst::ElementFactory::make("gtk4paintablesink")
|
let sink = gst::ElementFactory::make("gtk4paintablesink")
|
||||||
|
|
@ -33,37 +27,45 @@ pub fn create_camera_pipeline(name: &str, rtsp_uri: &str) -> Option<(Pipeline, E
|
||||||
|
|
||||||
let queue = gst::ElementFactory::make("queue")
|
let queue = gst::ElementFactory::make("queue")
|
||||||
.property("max-size-buffers", 1u32)
|
.property("max-size-buffers", 1u32)
|
||||||
.property("leaky", 2u32) // downstream
|
.property("leaky", 2u32)
|
||||||
.build()
|
.build()
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
pipeline.add_many([&src, &queue, &convert, &sink]).ok()?;
|
pipeline.add_many([&src, &decode, &queue, &convert, &sink]).ok()?;
|
||||||
gst::Element::link_many([&queue, &convert, &sink]).ok()?;
|
|
||||||
|
|
||||||
// rtspsrc has dynamic pads — connect on pad-added
|
// rtspsrc → decodebin (dynamic pads)
|
||||||
let queue_weak = queue.downgrade();
|
let decode_weak = decode.downgrade();
|
||||||
let pipeline_name_clone = pipeline_name.clone();
|
|
||||||
src.connect_pad_added(move |_src, pad| {
|
src.connect_pad_added(move |_src, pad| {
|
||||||
let caps = pad.current_caps().or_else(|| pad.query_caps(None));
|
let Some(decode) = decode_weak.upgrade() else { return };
|
||||||
let caps_str = caps.map(|c| c.to_string()).unwrap_or_default();
|
let sink_pad = decode.static_pad("sink").unwrap();
|
||||||
|
if !sink_pad.is_linked() {
|
||||||
// Only link video pads
|
let _ = pad.link(&sink_pad);
|
||||||
if !caps_str.contains("video") && !caps_str.contains("264") && !caps_str.contains("265") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
info!("[{pipeline_name_clone}] linking pad: {caps_str}");
|
|
||||||
|
|
||||||
let Some(queue) = queue_weak.upgrade() else { return };
|
|
||||||
if pad.link(&queue.static_pad("sink").unwrap()).is_err() {
|
|
||||||
warn!("[{pipeline_name_clone}] pad link failed");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// For decodebin-style pipelines, we might need more complex linking.
|
// decodebin → queue → convert → sink (dynamic pads, video only)
|
||||||
// For now, rtspsrc → queue → convert → sink works for raw decode.
|
let queue_weak = queue.downgrade();
|
||||||
// The actual decode happens if we insert depay+parse+decoder elements.
|
let pipeline_name_clone = pipeline_name.clone();
|
||||||
// TODO: auto-detect codec and insert appropriate decoder chain.
|
decode.connect_pad_added(move |_decode, pad| {
|
||||||
|
let caps = pad.current_caps().unwrap_or_else(|| pad.query_caps(None));
|
||||||
|
let caps_str = caps.to_string();
|
||||||
|
|
||||||
|
if !caps_str.starts_with("video/") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("[{pipeline_name_clone}] decodebin video pad: {caps_str}");
|
||||||
|
|
||||||
|
let Some(queue) = queue_weak.upgrade() else { return };
|
||||||
|
let sink_pad = queue.static_pad("sink").unwrap();
|
||||||
|
if !sink_pad.is_linked() {
|
||||||
|
if pad.link(&sink_pad).is_err() {
|
||||||
|
warn!("[{pipeline_name_clone}] decodebin pad link failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
gst::Element::link_many([&queue, &convert, &sink]).ok()?;
|
||||||
|
|
||||||
info!("[{pipeline_name}] pipeline created for {rtsp_uri}");
|
info!("[{pipeline_name}] pipeline created for {rtsp_uri}");
|
||||||
Some((pipeline, sink))
|
Some((pipeline, sink))
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::path::PathBuf;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tracing::{info, warn};
|
use tracing::info;
|
||||||
|
|
||||||
use crate::bundle::KioskBundle;
|
use crate::bundle::KioskBundle;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use gtk4::{self as gtk, Application, ApplicationWindow, Box as GtkBox, Grid, Lab
|
||||||
use gstreamer::prelude::*;
|
use gstreamer::prelude::*;
|
||||||
use tracing::{info, warn};
|
use tracing::{info, warn};
|
||||||
|
|
||||||
use crate::bundle::{BundleLayout, KioskBundle};
|
use crate::bundle::KioskBundle;
|
||||||
use crate::pipeline;
|
use crate::pipeline;
|
||||||
use crate::server;
|
use crate::server;
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ fn activate(app: &Application) {
|
||||||
let provider = gtk::CssProvider::new();
|
let provider = gtk::CssProvider::new();
|
||||||
provider.load_from_string("window { background-color: #1a1a2e; }");
|
provider.load_from_string("window { background-color: #1a1a2e; }");
|
||||||
gtk::style_context_add_provider_for_display(
|
gtk::style_context_add_provider_for_display(
|
||||||
&window.display(),
|
&WidgetExt::display(&window),
|
||||||
&provider,
|
&provider,
|
||||||
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
|
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue