Resource icon

Movies in PSDK

Pokémon Essentials Version
Non-applicable
Hi, I recently decided to try sfeMovie to add video playback in PSDK.

Since it's really heavy in term of dependencies (it add 50MB of dlls thus at least 50MB of RAM usage once loaded) I don't include it in PSDK natively. So this topic is here to tell you how to install it or build it :)

Windows Installation
1. Download this file: http://www.mediafire.com/file/bs26jpejg1p86sy/extract_in_your_project_(sfemovie).7z/file
2. Extract the file contents in your PSDK project

Linux/Mac Installation
1. Compile sfeMovie: http://sfemovie.yalir.org/latest/start.php
2. Compile Ruby SFEMovie: https://gitlab.com/NuriYuri/sfemovie (you need rake, it's built the same way as LiteRGSS so you can follow PSDK Wiki telling how to build PSDK under your OS)
3. Move the built file (SFEMovie.so/SFEMovie.bundle) to the root of your project.
4. Add the script (cf, script section) in your project.

The script
To install the script you need to create a file named "00001 Scene_Movie.rb" inside the scripts folder of your project (cf: https://psdk.pokemonworkshop.fr/wiki/en/manage/install-script.html).
Once the file is created, you can paste the following content in it:
Code:
module GamePlay
  # Scene responsive of playing a movie (video file)
  class Movie < BaseCleanUpdate
    # Constant telling if the BGM should automatically be stopped
    AUTO_STOP_BGM = true
    # Constant telling if the map scene should automatically be hidden
    AUTO_HIDE_MAP = true
    # Create a new Movie scene
    # @param filename [String] name of the file to play
    # @param aliased [Boolean] if the scene should use a viewport to ensure the video gets played in native resolution
    # @param skip_delay [Float] number of seconds the player has to wait before being able to skip the video
    def initialize(filename, aliased = false, skip_delay = Float::INFINITY)
      super(true)
      auto_require_movie_player
      @video = SFE::Movie.new
      @video.open_from_file(filename)
      @skip_delay = skip_delay
      @aliased = aliased
      @mutex = Mutex.new
    end

    def update_inputs
      return false unless @start_time
      
      dt = Graphics.current_time - @start_time
      if dt > @skip_delay && (Input.trigger?(:A) || Input.trigger?(:B) || Mouse.trigger?(:LEFT))
        @video.stop
        @running = false
      end
      
      return false
    end

    def update_graphics
      return start_video unless @start_time
      return @running = false unless @video.playing?
      @mutex.synchronize { @video.update_bitmap(@sprite.bitmap) }
      @video_thread.wakeup if @video_thread.status
    end

    private
    
    # Redefine main_end to show map again & clean up the space a bit
    def main_end
      @video_thread.kill
      @video_thread = nil
      @video = nil
      @__last_scene.sprite_set_visible = true if AUTO_HIDE_MAP && @__last_scene.is_a?(Scene_Map)
      super
    end
    
    # Function that create an aliased viewport
    def create_viewport
      super
      @viewport.blendmode = BlendMode.new
    end

    # Create all the graphics for the UI
    def create_graphics
      create_viewport if @aliased
      @sprite = Sprite.new(@viewport)
      add_disposable @sprite.bitmap = Bitmap.new(*@video.get_size.map(&:to_i))
      add_disposable @sprite unless @aliased
      width = @aliased ? @viewport.rect.width : Graphics.width
      height = @aliased ? @viewport.rect.height : Graphics.height
      @sprite.zoom = width / @sprite.width.to_f
      @sprite.y = (height - @sprite.height * @sprite.zoom_y).to_i / 2
      @__last_scene.sprite_set_visible = false if AUTO_HIDE_MAP && @__last_scene.is_a?(Scene_Map)
    end
    
    def auto_require_movie_player
      filename = PSDK_RUNNING_UNDER_WINDOWS ? 'lib/SFEMovie' : 'SFEMovie'
      filename += PSDK_RUNNING_UNDER_MAC ? '.bundle' : '.so'
      require filename
    end
    
    def start_video
      Audio.bgm_stop if AUTO_STOP_BGM
      @video.play
      @video.update
      @video.update_bitmap(@sprite.bitmap)
      @video_thread = Thread.new do
        while @video.playing?
          @mutex.synchronize { @video.update }
          sleep
        end
      end
      @start_time = Time.new
    end
  end
end

Note: I'm using a thread in this script to put the movie update process in another core of the CPU. This helps to save ~1000 Ruby FPS on a Ryzen 5 2600 compared to the single core version.

How to use
To use this script you need to call the scene GamePlay::Movie with at least 1 parameter.
Here's the parameter lists:
  • filename : String representing the filename of the movie to play, it may also include the path to the movie from the root of your project.
  • aliased : optional parameter telling if the movie should be aliased (in native resolution) or not.
  • skip_delay : optional parameter telling when (in seconds) the movie can be skipped by the player.
By default, the movie is not aliased and the player cannot skip the movie.

Here's a picture explaining the difference between aliased and not aliased:
Note: If your project uses a shader on the Graphics object, your video will always be aliased.

How to call the GamePlay::Movie scene
There's 3 situations.
1. If you're calling the scene from an event, you should call it like this:
Code:
$scene.call_scene(GamePlay::Movie, filename, aliased, skip_delay)
2. If you're calling from a GamePlay::Base / GamePlay::BaseCleanUpdate scene, you should call it like this:
Code:
call_scene(GamePlay::Movie, filename, aliased, skip_delay)
3. If you're calling from a non-standard scene, you should call it like this:
Code:
Graphics.freeze
GamePlay::Movie.new(filename, aliased, skip_delay).main
Graphics.transition #idk if that's necessary

Don't forget that you can omit aliased and skip_delay parameter!

Examples

Play a movie stored in Movies without aliasing and not letting the player to skip it:
Code:
$scene.call_scene(GamePlay::Movie, 'Movies/mymovie.mp4')
Play a movie stored in Movies without aliasing and letting the player skip after 5 seconds:
Code:
$scene.call_scene(GamePlay::Movie, 'Movies/mymovie.mp4', false, 5.0)
Play a movie stored in Movies with aliasing and letting the player skip after 3.5 seconds:
Code:
$scene.call_scene(GamePlay::Movie, 'Movies/mymovie.mp4', true, 3.5)
Play a movie stored in Movies with aliasing and not letting the player to skip it:
Code:
$scene.call_scene(GamePlay::Movie, 'Movies/mymovie.mp4', true)

Supported format
This script support a large variety of video format, you can use MP4 or WEBM instead of AVI. You can even use x265 encoded video for better performances :)
Credits
- SFML developers (originally Laurent Gomila)
- Loïc Siquet contributed to the Windows support of sfeMovie
- Alexandre Janniaux contributed to the Linux support of sfeMovie
- Martin Bohme as author of the FFmpeg tutorial at http://dranger.com/ffmpeg/
- Xorlium and timidouveg who worked on their own video integration packages from which was partly inspired sfeMovie (their wiki pages do no more exist)
- Stephan Vedder, who worked on subtitles support, integrated FFmpeg updates and continues to bring contributions today
- Nuri Yuri writer of the SFEMovie binding to PSDK

Note: The credit list may become outdated, please refer to this page to get the correct list: http://sfemovie.yalir.org/latest/developers.php
  • Like
Reactions: TechSkylander1518
Author
Nuri Yuri
Views
277
First release
Last update
Rating
0.00 star(s) 0 ratings

More resources from Nuri Yuri

Top