From a95d93d8a8454dc44bf0cdab5e04c329c8979773 Mon Sep 17 00:00:00 2001 From: porkbrain Date: Fri, 5 Jul 2024 15:41:15 +0200 Subject: [PATCH 1/5] Upgrading bevy and image --- Cargo.toml | 15 ++++++++------- README.md | 5 +++++ assets/image_crate_example.webp | Bin 0 -> 10818 bytes examples/basic.rs | 2 +- src/loader.rs | 9 ++++++++- src/types.rs | 20 ++++++++++++++------ 6 files changed, 36 insertions(+), 15 deletions(-) create mode 100644 assets/image_crate_example.webp diff --git a/Cargo.toml b/Cargo.toml index 513a2c6..e1aaa03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_webp_anim" -version = "0.3.1" +version = "0.4.0" edition = "2021" license = "MIT OR Apache-2.0" keywords = ["bevy", "webp", "video", "animation"] @@ -12,20 +12,21 @@ exclude = ["examples", "assets"] [dependencies] -image = "0.24" +image = "0.25" thiserror = "1.0" tokio = { version = "1.35", features = ["rt", "sync", "rt-multi-thread"] } - +uuid = "1.7" [dependencies.bevy] default-features = false features = ["bevy_asset", "bevy_render", "bevy_sprite"] -version = "0.13" +version = "0.14" + + +[dev-dependencies] +bevy = { version = "0.14", default-features = true } [[example]] name = "basic" path = "examples/basic.rs" - -[dev-dependencies] -bevy = { version = "0.13", default-features = true } diff --git a/README.md b/README.md index 7a51843..2dc137f 100644 --- a/README.md +++ b/README.md @@ -40,3 +40,8 @@ This would be useful if you play the same video in several places on your screen Right now, you'd need separate decoders and separate `Handle`. I don't need this feature in my project at the moment, but happy to add it if there's a demand. + +## Issue: Explore bevy's work load system instead of a custom tokio runtime + +Bevy comes with its own thread pool that can run tasks. +It might be preferable to use this instead of spawning another tokio runtime. diff --git a/assets/image_crate_example.webp b/assets/image_crate_example.webp new file mode 100644 index 0000000000000000000000000000000000000000..b65e6f7558a92589689c71eae4c80f3fc0d2a751 GIT binary patch literal 10818 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 literal 0 HcmV?d00001 diff --git a/examples/basic.rs b/examples/basic.rs index fa2d2a0..b96a512 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -17,7 +17,7 @@ fn main() { bevy_webp_anim::systems::load_next_frame, ), ) - .run() + .run(); } fn spawn_camera(mut commands: Commands) { diff --git a/src/loader.rs b/src/loader.rs index c2a9ed1..0073154 100644 --- a/src/loader.rs +++ b/src/loader.rs @@ -1,6 +1,7 @@ use bevy::{ asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext}, prelude::*, + utils::ConditionalSendFuture, }; use thiserror::Error; @@ -27,7 +28,13 @@ impl AssetLoader for WebpLoader { reader: &'a mut Reader, _settings: &'a Self::Settings, load_context: &'a mut LoadContext, - ) -> bevy::utils::BoxedFuture<'a, Result> { + ) -> impl ConditionalSendFuture + + std::future::Future< + Output = Result< + ::Asset, + ::Error, + >, + > { Box::pin(async move { let mut bytes = Vec::new(); reader.read_to_end(&mut bytes).await?; diff --git a/src/types.rs b/src/types.rs index 0439165..242735a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,4 +1,4 @@ -use std::{collections::BTreeMap, marker::PhantomData}; +use std::{collections::BTreeMap, io::Cursor, marker::PhantomData}; use bevy::{ prelude::*, @@ -6,11 +6,11 @@ use bevy::{ render_asset::RenderAssetUsages, render_resource::{Extent3d, TextureDimension, TextureFormat}, }, - utils::Uuid, }; use image::{codecs::webp::WebPDecoder, AnimationDecoder}; use tokio::sync::mpsc::{Receiver, Sender}; pub use tokio::{runtime, sync::mpsc::error::TryRecvError}; +use uuid::Uuid; /// See [`WebpAnimator::prepared_frames_count`]. pub const DEFAULT_PREPARED_FRAMES_COUNT: usize = 16; @@ -185,6 +185,14 @@ impl WebpVideo { pub async fn produce(self, animation_frames: Sender) { let WebpVideo { bytes, label } = self; + let decoder = match WebPDecoder::new(Cursor::new(bytes)) { + Ok(decoder) => decoder, + Err(e) => { + error!("Cannot construct webp decoder {label}: {e}"); + return; + } + }; + // We decode each frame only once and then play them over and // over. // This is optimized for replaying and low CPU usage. @@ -192,9 +200,7 @@ impl WebpVideo { // TODO: Enable an alternative with lower memory usage and // faster startup times where we decode each frame every time // it is played. - match WebPDecoder::new(bytes.as_slice()) - .and_then(|decoder| decoder.into_frames().collect_frames()) - { + match decoder.into_frames().collect_frames() { Ok(frames) => loop { for frame in &frames { let (width, height) = frame.buffer().dimensions(); @@ -216,7 +222,9 @@ impl WebpVideo { } } }, - Err(e) => error!("Cannot load webp video {label}: {e}"), + Err(e) => { + error!("Cannot collect webp frames from video {label}: {e}") + } }; } } From 02bc2361dd6675c2fb4739148ce3c4cf7dee4c32 Mon Sep 17 00:00:00 2001 From: porkbrain Date: Fri, 5 Jul 2024 16:12:12 +0200 Subject: [PATCH 2/5] CI runs more checks --- .github/workflows/rust.yml | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 31000a2..206d5cb 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,21 +2,31 @@ name: Rust on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] env: CARGO_TERM_COLOR: always jobs: build: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Build - run: cargo build --verbose - - name: Run tests - run: cargo test --verbose + - uses: actions/checkout@v4 + + - name: Install dependencies + run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev + - name: Version check + run: rustc --version && cargo --version && rustfmt --version && cargo clippy --version + - name: Format + run: cargo fmt -- --check + - name: Check + run: cargo check + - name: Clippy + run: cargo clippy -- -D warnings + - name: Test + run: cargo test + - name: Broken docs + run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --offline From bfc4f9ed0afdbef92ad7ac78f5ec240b0a08c713 Mon Sep 17 00:00:00 2001 From: porkbrain Date: Fri, 5 Jul 2024 16:14:32 +0200 Subject: [PATCH 3/5] Fixing code styles --- src/loader.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/loader.rs b/src/loader.rs index 0073154..128dcea 100644 --- a/src/loader.rs +++ b/src/loader.rs @@ -28,8 +28,7 @@ impl AssetLoader for WebpLoader { reader: &'a mut Reader, _settings: &'a Self::Settings, load_context: &'a mut LoadContext, - ) -> impl ConditionalSendFuture - + std::future::Future< + ) -> impl ConditionalSendFuture< Output = Result< ::Asset, ::Error, From fbd0319b83253b37266f53a58a40f3aa18c11f3a Mon Sep 17 00:00:00 2001 From: porkbrain Date: Fri, 5 Jul 2024 17:26:56 +0200 Subject: [PATCH 4/5] Temporary fix for an upstream bug --- Cargo.toml | 1 + src/types.rs | 73 +++++++++++++++++++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e1aaa03..1f74479 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ exclude = ["examples", "assets"] [dependencies] image = "0.25" +image-webp = "*" # we want the one that image uses thiserror = "1.0" tokio = { version = "1.35", features = ["rt", "sync", "rt-multi-thread"] } uuid = "1.7" diff --git a/src/types.rs b/src/types.rs index 242735a..b78f19c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -7,7 +7,7 @@ use bevy::{ render_resource::{Extent3d, TextureDimension, TextureFormat}, }, }; -use image::{codecs::webp::WebPDecoder, AnimationDecoder}; +use image::{codecs::webp::WebPDecoder, AnimationDecoder, ImageError}; use tokio::sync::mpsc::{Receiver, Sender}; pub use tokio::{runtime, sync::mpsc::error::TryRecvError}; use uuid::Uuid; @@ -200,31 +200,58 @@ impl WebpVideo { // TODO: Enable an alternative with lower memory usage and // faster startup times where we decode each frame every time // it is played. - match decoder.into_frames().collect_frames() { - Ok(frames) => loop { - for frame in &frames { - let (width, height) = frame.buffer().dimensions(); - let image = Image::new( - Extent3d { - width, - height, - ..default() - }, - TextureDimension::D2, - frame.clone().into_buffer().into_raw(), - TextureFormat::Rgba8Unorm, - RenderAssetUsages::RENDER_WORLD, - ); - // animation no longer required - if animation_frames.send(image).await.is_err() { - break; + // we need to collect because we send the frames over an async channel + let frames: Vec<_> = decoder + .into_frames() + .take_while(|frame_res| match frame_res { + Ok(_) => true, + Err(ImageError::Decoding(err)) => { + use std::error::Error; + if let Some(image_webp::DecodingError::NoMoreFrames) = + err.source().and_then(|err| { + err.downcast_ref::() + }) + { + // iterator ended + // TODO: https://github.com/image-rs/image/issues/2263 + } else { + error!( + "Cannot decode webp frame from video {label}: {:?}", + err.source() + ); } + + false } - }, - Err(e) => { - error!("Cannot collect webp frames from video {label}: {e}") + Err(e) => { + error!( + "Cannot collect webp frames from video {label}: {e}" + ); + false + } + }) + .filter_map(Result::ok) + .collect(); + + for frame in frames { + let (width, height) = frame.buffer().dimensions(); + let image = Image::new( + Extent3d { + width, + height, + ..default() + }, + TextureDimension::D2, + frame.clone().into_buffer().into_raw(), + TextureFormat::Rgba8Unorm, + RenderAssetUsages::RENDER_WORLD, + ); + + // animation no longer required + if animation_frames.send(image).await.is_err() { + break; } - }; + } } } From 0df5dadfd164afc2d47f426989f1680d062bcabf Mon Sep 17 00:00:00 2001 From: porkbrain Date: Fri, 5 Jul 2024 17:29:03 +0200 Subject: [PATCH 5/5] Loop the webp video --- src/types.rs | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/types.rs b/src/types.rs index b78f19c..c3d0be4 100644 --- a/src/types.rs +++ b/src/types.rs @@ -234,23 +234,25 @@ impl WebpVideo { .filter_map(Result::ok) .collect(); - for frame in frames { - let (width, height) = frame.buffer().dimensions(); - let image = Image::new( - Extent3d { - width, - height, - ..default() - }, - TextureDimension::D2, - frame.clone().into_buffer().into_raw(), - TextureFormat::Rgba8Unorm, - RenderAssetUsages::RENDER_WORLD, - ); - - // animation no longer required - if animation_frames.send(image).await.is_err() { - break; + loop { + for frame in &frames { + let (width, height) = frame.buffer().dimensions(); + let image = Image::new( + Extent3d { + width, + height, + ..default() + }, + TextureDimension::D2, + frame.clone().into_buffer().into_raw(), + TextureFormat::Rgba8Unorm, + RenderAssetUsages::RENDER_WORLD, + ); + + // animation no longer required + if animation_frames.send(image).await.is_err() { + break; + } } } }