Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
612 changes: 424 additions & 188 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ members = [
"crates/tauri-bundler",
"crates/tauri-macos-sign",
"crates/tauri-driver",
"crates/tauri-asset-gst-plugin",


# @tauri-apps/cli rust project
"packages/cli",
Expand Down
1 change: 1 addition & 0 deletions crates/tauri-asset-gst-plugin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
27 changes: 27 additions & 0 deletions crates/tauri-asset-gst-plugin/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "tauri-asset-gst-plugin"
version = "0.1.0"
authors = ["Alexander Yanovskyy <contact@yanovskyy.com>"]
license = "MIT OR Apache-2.0"
edition = "2018"
repository = "https://github.com/tauri-apps/tauri"
description = "Gstreamer plugin for asset protocol"

[dependencies]
gstreamer = "0.24"
gstreamer-base = "0.24"
percent-encoding = "2.3.2"

[lib]
name = "gsttauriasset"
crate-type = ["cdylib"]
path = "src/lib.rs"

[build-dependencies]
gst-plugin-version-helper = "0.8.3"

[profile.release]
lto = true
codegen-units = 1
opt-level = "z"
panic = 'abort'
3 changes: 3 additions & 0 deletions crates/tauri-asset-gst-plugin/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
gst_plugin_version_helper::info();
}
20 changes: 20 additions & 0 deletions crates/tauri-asset-gst-plugin/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use gst::glib;
use gstreamer_base::gst;

mod tauri_asset;

fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
tauri_asset::register(plugin)
}

gst::plugin_define!(
tauriasset,
env!("CARGO_PKG_DESCRIPTION"),
plugin_init,
concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMIT_ID")),
"The Plugin's License",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_REPOSITORY"),
env!("BUILD_REL_DATE")
);
104 changes: 104 additions & 0 deletions crates/tauri-asset-gst-plugin/src/tauri_asset/imp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use gst::glib::subclass::types::ObjectSubclassExt;
use gst::prelude::{ElementExt, GhostPadExt, GstBinExt, PadExt};
use gst::subclass::prelude::{BinImpl, ElementImpl, ObjectImpl, URIHandlerImpl};
use gst::subclass::prelude::{GstObjectImpl, ObjectSubclass};
use gst::{glib, GhostPad, PadDirection};
use gstreamer_base::gst;

const ASSET_URI_SCHEME: &str = "asset";

#[derive(Default)]
pub struct TauriAsset {
// uri: Option<String>,
}

impl TauriAsset {
pub fn new() -> Self {
Self::default()
}
}

#[glib::object_subclass]
impl ObjectSubclass for TauriAsset {
const NAME: &'static str = "GstTauriAsset";
type Type = super::TauriAsset;
type ParentType = gst::Bin;
type Interfaces = (gst::URIHandler,);
}

impl GstObjectImpl for TauriAsset {}
impl ObjectImpl for TauriAsset {}
impl BinImpl for TauriAsset {}
impl ElementImpl for TauriAsset {}

impl URIHandlerImpl for TauriAsset {
const URI_TYPE: gst::URIType = gst::URIType::Src;

fn protocols() -> &'static [&'static str] {
&[ASSET_URI_SCHEME]
}

fn uri(&self) -> Option<String> {
None
Copy link
Author

@aaalloc aaalloc Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it should be like this, but I don't think it is a problem for now

}

fn set_uri(&self, uri: &str) -> Result<(), glib::Error> {
// uri is like: asset://path/to/asset or asset://localhost/path/to/asset
let sep = format!("{}://", ASSET_URI_SCHEME);
let mut split = uri.split(sep.as_str());
let location = split
.nth(1)
.ok_or_else(|| glib::Error::new(gst::URIError::BadUri, "Could not get location from URI"))?;

// directly having full path after asset:// or having localhost
let location = location.strip_prefix("localhost").unwrap_or(location);

// Uri could be percent-encoded
let location = percent_encoding::percent_decode_str(location)
.decode_utf8()
.map_err(|_| {
glib::Error::new(
gst::URIError::BadUri,
"Could not decode percent-encoded URI",
)
})?
.to_string();

// now location is like: /path/to/asset
let internal_src = gst::ElementFactory::make("filesrc")
.name("filesrc")
.property("location", location)
.build()
.ok();

let element = self.obj();
element
.add(internal_src.as_ref().unwrap())
.expect("Failed to add internal source");

let srcpad = internal_src
.as_ref()
.and_then(|src| src.static_pad("src"))
.ok_or_else(|| {
glib::Error::new(
gst::URIError::BadUri,
"Could not get src pad from internal source",
)
})?;

let ghostpad = GhostPad::new(PadDirection::Src);
ghostpad
.set_target(Some(&srcpad))
.ok()
.ok_or_else(|| glib::Error::new(gst::URIError::BadUri, "Could not create ghost pad"))?;

ghostpad
.set_active(true)
.ok()
.ok_or_else(|| glib::Error::new(gst::URIError::BadUri, "Could not activate ghost pad"))?;

let element = self.obj();
element.add_pad(&ghostpad).expect("Failed to add ghost pad");
Ok(())
}
}
20 changes: 20 additions & 0 deletions crates/tauri-asset-gst-plugin/src/tauri_asset/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use gst::glib;
use gst::prelude::*;
use gstreamer_base::gst;

mod imp;

glib::wrapper! {
pub struct TauriAsset(ObjectSubclass<imp::TauriAsset>)
@extends gst::Bin, gst::Element, gst::Object,
@implements gst::URIHandler;
}

pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
gst::Element::register(
Some(plugin),
"tauriasset",
gst::Rank::PRIMARY,
TauriAsset::static_type(),
)
}