Crate bevy_capture

source ·
Expand description

§bevy_capture

crates.io docs.rs

A Bevy plugin for capturing frames from a Bevy application. It comes with some built-in encoders, e.g. for creating gifs or videos, and can be easily extended with custom encoders.

§Current Limitations

  • Only headless rendering is supported, but windowed rendering should be possible as well. PRs are welcome!
  • There isn’t a built-in method to determine when everything is ready (such as assets loaded and pipelines built). The best approach is to wait a few frames before starting the capture.

§Built-in Encoders

NameDescriptionRequired Features
FramesEncoderEncodes frames into individual images.
GifEncoderEncodes frames into a gif.gif
Mp4Openh264Encoder*⚠️Encodes frames into an mp4 using openh264.mp4_openh264
Mp4FfmpegCliEncoderEncodes frames into an mp4 using the ffmpeg CLI (ffmpeg must be in PATH).mp4_ffmpeg_cli

*⚠️ The Mp4Openh264Encoder is incomplete and does not work properly yet. PRs are welcome!

§Usage

For a complete example, see the simple example.

// Add plugins
app.add_plugins((
    // Disable the WinitPlugin to prevent the creation of a window
    DefaultPlugins.build().disable::<WinitPlugin>(),
    // Add the ScheduleRunnerPlugin to run the app in loop mode
    ScheduleRunnerPlugin {
        run_mode: RunMode::Loop { wait: None },
    },
    // Add the CapturePlugin
    bevy_capture::CapturePlugin,
));

// Spawn a camera with the CaptureBundle
fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
  commands.spawn((
      Camera2dBundle::default().target_headless(512, 512, &mut images),
      CaptureBundle::default(),
  ));
}

// Start capturing
fn update(mut capture: Query<&mut Capture>) {
  let mut capture = capture.single_mut();
  if !capture.is_capturing() {
    capture.start(
      GifEncoder::new(File::create("my_capture.gif").unwrap())
        .with_repeat(gif::Repeat::Infinite)
    );
  }
}

§Implementing a Custom Encoder

struct MyCustomEncoder;

impl Encoder for MyCustomEncoder {
    fn encode(&mut self, image: &Image) -> Result<()> {
        // Called for each frame.
        todo!("Encode the image into your custom format.")
    }

    fn finish(self: Box<Self>) {
      // Called when the encoder is stopped.
      todo!("Finish encoding the frames, if necessary.")
    }
}

§License

Licensed under either of

at your option.

Modules§

  • Encoders for different formats.

Structs§

Enums§

Traits§

  • Extension trait for the camera to set the target to a headless image. This is implemented for Camera, Camera2dBundle, and Camera3dBundle.
  • An encoder that encodes a sequence of images into a custom format.
  • Convert a value into a sequence of encoders.