1. All Unity Pro perpetual license customers: your special offer to subscribe is ready! Click here.
  2. We're running a survey about the usage of our graphics pipeline, help give us your feedback.
  3. Unity 5.6 beta is now available for download.
  4. Unity 5.5 is now released.
  5. Check out all the fixes for 5.5 in patch releases 1 & 2.
  6. Enter the Google Play Indie Games Contest in Europe. Read more about it here.
  7. Get prepared for the Tizen Mobile App Incentive Program! Read more about the upcoming program here.
  8. Enter the Microsoft Developer Challenge for a chance to win prizes. Read more about it here.

Movie Player for Indie Users

Discussion in 'Made With Unity' started by wbokunic, Jun 20, 2010.

  1. wbokunic

    wbokunic

    Joined:
    Dec 17, 2009
    Messages:
    43
    I've seen a few threads where users of Unity Indie were wanting to play movie clips and such. Since this is a Pro feature, you can't, obviously, play movies in Unity Indie. However, you can play a series of stills in Unity Indie to create the illusion of video.

    So, what I've done is created a [crude and] simple-to-use script for Unity Indie users to play movie clips. Here's the web demo (note - you might need to refresh the page after the initial load for the video to be in-sync).

    [​IMG]

    https://dl.dropbox.com/u/7181231/builds/MovieScene/moviescene.html

    Before you use:

    1) Compress your video so that it is exactly a certain number of frames. It cannot be something like 29.97 frames per second. It needs to be something like 30 frames per second.

    2) Use a program (like VirtualDub) to convert the video into a series of still images.

    3) Use a program like Audacity to strip out the audio into an .mp3 or something similar.

    Now that we've cleared that out of the way, here's how you use it!

    How to use:

    1) Drop the script on an object, preferably a plane (though it can be anything). Also make sure to set a material. It can be a blank texture though.

    2) Configure the options to your liking. Set the "Number_of_stills" value to the number of "Movie_stills" you have (there's probably a way to grab this number, but I got a bit lazy lol). Determine if you want the video to loop, set the fps and/or attach an audio file.

    3) Make sure "sync to VBL" is enable in the quality settings. Otherwise the video and audio might get out of sync (only needed if you use an audio clip).

    4) Load the level and see how it runs!

    I tried to give the user a few options. So it is optional if you want to use audio or not, as well as if you want the video to loop or not. If the movie ends before the audio does, the audio will stop as well too. It's also set up in a way that almost anyone could go in and tweak it for their own needs (enabled when the user presses "E" on it for instance).

    Do heavily note though: This method is a pain. The video demo I recorded was roughly 9 seconds long, meaning I had over 270 still images I needed to manually drop in one at a time. So I'd use this script sparingly.

    [​IMG]

    Code (csharp):
    1. var movie_stills : Texture[] = new Texture[1];
    2. var number_of_stills = 1;
    3. var Loop = false;
    4. var fps = 30;
    5. var Sound : AudioClip;
    6.  
    7. private var stills = 0;
    8. private var play = true;
    9.  
    10. function Update () {
    11.     if(fps > 0){
    12.         if(play == true){
    13.             Player();
    14.         }
    15.     } else {
    16.           Debug.LogError("'fps' must be set to a value greater than 0.");
    17.     }
    18. }
    19.  
    20. function Player(){
    21.     play = false;
    22.     if(Loop){
    23.         if(stills > number_of_stills) {
    24.             audio.Stop();
    25.             audio.clip = Sound;
    26.             audio.Play();
    27.             stills = 0;
    28.         }
    29.     } else {
    30.         if(stills > number_of_stills) {
    31.             audio.Stop();
    32.             stills -= 1;
    33.         }
    34.     }
    35.     var MainTex = movie_stills[stills];
    36.     renderer.material.SetTexture("_MainTex", MainTex);
    37.     stills += 1;
    38.     var fps_fixer = fps*3;
    39.     var wait_time = 1.0/fps_fixer;
    40.     yield WaitForSeconds(wait_time);
    41.     if(!audio.clip){
    42.         if(Sound){
    43.             audio.clip = Sound;
    44.             audio.Play();
    45.         }
    46.     }
    47.     play = true;
    48. }
    49.  
    50. function Start ()
    51. {
    52.     audio.loop = false;
    53.     number_of_stills -= 1;
    54. }
    55.  
    56. @script RequireComponent(AudioSource)
     
  2. Blacklight

    Blacklight

    Joined:
    Dec 6, 2009
    Messages:
    1,167
    You've beaten the system! :D

    It isn't the most elegant way of doing things, but you did a good job.
     
  3. GeneralGrant

    GeneralGrant

    Joined:
    Jun 10, 2010
    Messages:
    977
    amazing!




    I see you...
     
  4. wbokunic

    wbokunic

    Joined:
    Dec 17, 2009
    Messages:
    43
    Yes, you see me being very tired lol.

    I actually made this for doing simple animations of images, versus doing full blown sprite support, since this is easier to manage. Figured I'd upgrade it a bit for full movie support and release it since quite a few Indie users have requested it.
     
  5. Caliber-Mengsk

    Caliber-Mengsk

    Joined:
    Mar 24, 2010
    Messages:
    678
    hmmm... I wonder how easy it would be to make a simple VB app that would use FFMPEG to convert the video to frames, and the audio to mp3/ogg...


    ....... May have to look into this.

    Unfortunately, this method would make really really large downloads if you had a lot of video.
     
  6. wbokunic

    wbokunic

    Joined:
    Dec 17, 2009
    Messages:
    43
    Yeah. The recorded video was about 5 MB. Breaking up all the frames into images and the audio as well resulted in about a 1 mb increase. So not much different from using real video. Just use it sparingly.
     
  7. Imari

    Imari

    Joined:
    May 26, 2010
    Messages:
    24
    Whoa, thank you!
     
  8. rtumelty

    rtumelty

    Joined:
    Dec 11, 2011
    Messages:
    11
    Hi, great script! The amount of setup seemed rather extreme though. I've adapted it so that the script will automatically load the images from a subfolder of Resources. At the moment, that's done at runtime - I may change it so that the user can force a load from within the editor at some point (for that little less overhead). The audio clip must still be added manually, but with a minor change it can load an audiofile from the same folder as the image sequence. I ported it to C# also, mostly out of personal preference. I've tested it on PC and Android. You can find the code below.

    A note on my implementation: it requires that you store the images in a subfolder of Assets/Resources. Anything here will be added to the build, whether it's used or not, as the engine ignores the Resources folder for optimising. So if you decide not to use any resources, make sure to delete them from the folder before building to keep your filesize down!

    But yeah, great workaround!

    Ronan Tumelty

    Code (csharp):
    1.  
    2. // Original script by wbokunic - http://forum.unity3d.com/threads/52001-Movie-Player-for-Indie-Users
    3. // Modified C# version by Ronan Tumelty
    4.  
    5. using UnityEngine;
    6. using System.Collections;
    7. using System.IO;
    8.  
    9. [RequireComponent(typeof(AudioSource))]
    10. public class VideoPlayer : MonoBehaviour {
    11.     Object[] movie_stills;
    12.     int number_of_stills = 0;
    13.     public bool loop = false;
    14.     public bool playOnStart = false;
    15.     public int fps = 30;
    16.     public AudioClip sound;
    17.     public string resourceSubfolder = "";
    18.      
    19.     private int stills = 0;
    20.     private bool play = false;
    21.     private bool loaded = false;
    22.      
    23.     void Update () {
    24.        
    25.         if (!resourceSubfolder.Equals("")  !loaded) {
    26.             StartCoroutine(ImportVideo());
    27.         }
    28.        
    29.         if(fps > 0){
    30.             if(play == true){
    31.                 StartCoroutine(Player());
    32.             }
    33.         } else {
    34.               Debug.LogError("'fps' must be set to a value greater than 0.");
    35.         }  
    36.     }
    37.      
    38.     IEnumerator Player(){
    39.         play = false;
    40.         if(loop){
    41.             Debug.Log("looped. stills: " + stills + ", length: " + movie_stills.Length);
    42.             if(stills >= movie_stills.Length) {
    43.                 audio.Stop();
    44.                 audio.clip = sound;
    45.                 audio.Play();
    46.                 stills = 0;
    47.                 Debug.Log("restarting. stills: " + stills);
    48.             }
    49.         } else {
    50.             if(stills > movie_stills.Length) {
    51.                 audio.Stop();
    52.                 stills -= 1;
    53.             }
    54.         }
    55.        
    56.         if (stills >= 0  stills < movie_stills.Length) {
    57.             Texture2D MainTex = movie_stills[stills] as Texture2D;
    58.             renderer.material.SetTexture("_MainTex", MainTex);
    59.             stills += 1;
    60.             int fps_fixer = fps*3;
    61.             float wait_time = 1.0f/fps_fixer;
    62.             yield return new WaitForSeconds(wait_time);
    63.             if(!audio.clip){
    64.                 if(sound){
    65.                     audio.clip = sound;
    66.                     audio.Play();
    67.                 }
    68.             }
    69.             play = true;
    70.         }
    71.     }
    72.    
    73.     public void Play() { play = true; }
    74.     public void Pause() { play = false; }
    75.      
    76.     void Start ()
    77.     {
    78.         audio.loop = false;
    79.         number_of_stills -= 1;
    80.     }
    81.    
    82.    
    83.     IEnumerator ImportVideo() {
    84.         movie_stills = Resources.LoadAll(resourceSubfolder, typeof(Texture2D));
    85.         loaded = true;
    86.         if (playOnStart)
    87.             play = true;   
    88.         yield return null;
    89.     }
    90.    
    91.     public void UnloadFromMemory() {
    92.         play = false;
    93.         audio.Stop();
    94.        
    95.         foreach (Object o in movie_stills) Destroy(o);
    96.     }
    97. }
    98.  
     
  9. ThomQ

    ThomQ

    Joined:
    Nov 23, 2010
    Messages:
    297
    Great Job, Going to test it on mobile tonight, let you know the results!
     
  10. rahuxx

    rahuxx

    Joined:
    May 8, 2009
    Messages:
    488
    any way to use actual MP4 video from resource folder, in place of still images.
     
  11. TAGGEDGAMES

    TAGGEDGAMES

    Joined:
    Mar 6, 2013
    Messages:
    43
    Wow great job.
     
  12. moss18

    moss18

    Joined:
    Jan 14, 2013
    Messages:
    1
  13. SaudAli3

    SaudAli3

    Joined:
    Nov 5, 2013
    Messages:
    2
    Can We use mp4 video file instead of still images?