Loading Movies from Disk in Unity 5 - c#

I'm using Unity 5 and C# and I would like to load a movie from anywhere on disk at run-time rather than from the Resources folder.
This is possible to do with regular image textures using the .LoadImage (bytes) method in Texture2D type for example, but there does not appear to be an equivalent for MovieTexture.
The code shows how to do it from the resources folder, but how could i modify it to load from disk?
Thanks
public void loadVideo (GameObject container, string video)
{
// Load MovieTexture from Resources Folder
MovieTexture mat = (MovieTexture)Resources.Load(Path.GetFileNameWithoutExtension(video), typeof(MovieTexture));
MeshRenderer ren = container.GetComponent<MeshRenderer>();
ren.material.mainTexture = mat;
mat.Play();
}

You can. Use the WWW class to to this.
IEnumerator loadAndPlay(){
WWW diskMovieDir = new WWW("file:///C:/yourvideoDir/video.mp4");
//Wait for file finish loading
while(!diskMovieDir.isDone){
yield return null;
}
//Save the loaded movie from WWW to movetexture
MovieTexture movieToPlay = diskMovieDir.movie;
//Hook the movie texture to the current renderer
MeshRenderer ren = container.GetComponent<MeshRenderer>();
ren.material.mainTexture = movieToPlay ;
movieToPlay.play();
}
Now you can call it by starting coroutine.
StartCoroutine(loadAndPlay());
I did not compile this so there might be a compile error but you can easily fix it if there is one. This should also work without problems if it compiles. Note that the url must start with file:///. If that didnt work, try file://

Related

How do I take a screenshot of the current view of my desktop app in Unity using C#?

I have a desktop application that I have made on Unity and I want to take a screenshot of my current view in the application using a C# script attached to the main camera. Please help.
I have browsed other code snippets that I found on this platform and nothing seemed to help.
You can use CaptureScreenshot.
public class ScreenCapture : MonoBehaviour
{
//here you can set the folder you want to use,
//IMPORTANT - use "#" before the string, because this is a verbatim string
//IMPORTANT - the folder must exists
string pathToYourFile = #"C:\Screenshots\";
//this is the name of the file
string fileName = "filename";
//this is the file type
string fileType = ".png";
private int CurrentScreenshot { get => PlayerPrefs.GetInt("ScreenShot"); set => PlayerPrefs.SetInt("ScreenShot", value); }
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
UnityEngine.ScreenCapture.CaptureScreenshot(pathToYourFile + fileName + CurrentScreenshot + fileType);
CurrentScreenshot++;
}
}
}
A few notes.
I used a verbatim string to define your folder
The folder where you store the screenshot must exist (if you want to create it in the script you can follow this answer)
AFTER COMMENT REQUEST - 1: If you do not set the folder the file will be saved in the default directory of the application (that changes based on the system - you can check it from Application.dataPath)
AFTER COMMENT REQUEST - 2: If you use the same path and filename the file will be overriden, so I added a way to let you save multiple screenshots, also in different sessions using PlayerPrefs.
You can use CaptureScreenshot method as answered above but it might be confusing for you if you are new to unity. It stores your captures image in a filepath which you should pass to CaptureScreenshot method as parameter for example
public class ScreenShotManager : MonoBehaviour {
const string FilePath = #"C:\Users\UserName\Desktop\ScreenShots";
public void CaptureScreenShot() {
ScreenCapture.CaptureScreenshot(FilePath);
}
void Update(){
if(Input.GetKeyDown(Keycode.C))
CaptureScreenShot();
}
this code shows that if you press 'c' key on keyboard it would be captured what main camera is rendering at that moment and stored in that file path

errors loading assetbundle in unity

I'll start with the errors themselves. The first is : Assertion failed on expression: 'm_UncompressedBlocksOffsets[blockInd] <= from + dstPos && m_UncompressedBlocksOffsets[blockInd] + uncompressedBlockSize >= from + dstPos' UnityEngine.AssetBundle:LoadFromFile(String)
Followed by : Failed to decompress data for the AssetBundle 'D:/Unity/projects/PQv0.10/Assets/AssetBundles/spritesbundle'. UnityEngine.AssetBundle:LoadFromFile(String)
I've always just used the resources folder for my projects but my current project has outgrown what that method can accommodate. So I'm trying to offload assets (in this case 5000 or so sprites)into an assetbundle and load them as needed at runtime. I figured I could just get a reference to the assetbundle and then call assetbundle.LoadAsset(assetname), substituting my old Resources.Load calls. Here's my attempt at making the assetbundle reference that keeps erroring:
AssetBundle sprites;
void loadSprites()
{
sprites = AssetBundle.LoadFromFile(Application.dataPath + "/AssetBundles/spritesbundle"); // " + bundleName);
if (!sprites) {
Debug.Log("failed to load assetbundle");
}
}
For due diligence, here's also the code I used to create that assetbundle. It simple searches my project for png's and packs them into the assetbundle:
public static void SaveSpecificAssets()
{
AssetBundleBuild build = new AssetBundleBuild();
build.assetBundleName = "spritesBundle";
string[] files = AssetDatabase.GetAllAssetPaths();
List<string> validFiles = new List<string>();
foreach (string file in files)
{
if (file.EndsWith(".png")) validFiles.Add(file);
}
build.assetNames = validFiles.ToArray();
BuildPipeline.BuildAssetBundles("Assets/AssetBundles", new AssetBundleBuild[1] { build }, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
}
The assetbundle builds without errors and appears in the directory where it should be. I have no indication that it's faulty other than the errors I get when trying to load it. The manifest it generates contains appropriate items so I think it's working as intended at least.If I'm missing any relevant information, please point it out and I'll try to provide it.
this is the test coroutine I used in place of loadSprites() for testing if it made a difference:
IEnumerator testLoader()
{
WWW www = WWW.LoadFromCacheOrDownload("file:///" + Application.dataPath + "/AssetBundles/spritesbundle", 1);
yield return www;
sprites = www.assetBundle;
}
Try this, for all the PNG's in your project folder, select them all and add them to an AssetBundle via the Editor, Then just build using
BuildPipeline.BuildAssetBundles("Assets/AssetBundles",BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
Then try to load the bundles and see if it shows an error.
Also, look into the Manifest to see if all the files you intended are listed

How to stream/download&play an audio from URL?

I need to stream or download and play an audio getted from an URL in Unity3D, running on iOS.
The Audio comes from a text-to-audio service and I need to play it on Unity:
http://api.ispeech.org/api/rest?apikey=...&action=convert&voice=eurspanishfemale&text=hola+que+tal
I've been googling all the morning and not found a valid solution...
There is a code snippet in the Unity3D documentation (WWW-audioClip,WWW.GetAudioClip), but is not working, I have debugged and the error says it couldn't open the file.
using UnityEngine;
using System.Collections;
public class AudioURLScript : MonoBehaviour {
public string url = "http://api.ispeech.org/api/rest?apikey=...&action=convert&voice=eurspanishfemale&text=hola+que+tal";
public AudioSource source;
void Start() {
WWW www = new WWW("file://"+url);
source = GetComponent<AudioSource>();
source.clip = www.GetAudioClip(false,true);
}
void Update() {
if (!source.isPlaying && source.clip.isReadyToPlay)
source.Play();
}
}
Thanks
SOLUTION
This is my working solution right now.
void Start(){
StartCoroutine(DownloadAndPlay("http://api.ispeech.org/api/rest?apikey=...&action=convert&voice=eurspanishfemale&text=Hola+que+tal"));
}
IEnumerator DownloadAndPlay(string url)
{
WWW www = new WWW(url);
yield return www;
AudioSource audio = GetComponent<AudioSource>();
audio.clip = www.GetAudioClip(false, true,AudioType.MPEG);
audio.Play();
}
You don't mention the platform you are on, so I'm going to assume Windows.
Unity Windows runtime only supports WAV or OGG. The link to the audio service file you provided is downloading as a MP2 Audio File (common in broadcasting). Unity will not be able to play that (or MP3).
For reference, Android and iOS platforms do support MP3 (but not MP2).
So, you're first issue is to make sure your audio source is in compatible format.
The code sample is incorrect for 3 reasons;
the URL is https: (which tells unity to download from the internet) but then you pre-pend file: to it (which tells unity to load from the local file system). So you should pick one or the other.
it wouldn't work if you picked https because that particular link (I know it's just an example) but it requires a user to be logged in to the service (and using cookies to know that), so it doesn't send you an audio file, it sends you a HTML page telling the user to login or register.
As #fafase says, the WWW must be placed within a co-routine, so that it can download over multiple frames.
OK, here's what I suggest.
If you can know the audio files a head of time, download them and transcode to OGG (if windows) or MP3 (if mobile) and upload them to your own server (say Amazon S3, or a $10 a month unlimited website).
Then, use this code to download and play it:
StartCoroutine(DownloadAndPlay("http://myserver.com/audio/test.ogg"));
IEnumerator DownloadAndPlay(string url)
{
WWW www = new WWW(url);
yield return www;
AudioSource audio = GetComponent<AudioSource>();
audio.clip = www.GetAudioClip(false, false);
audio.Play();
}
A WWW object is a wrapper for a HTTP request, containing the creation of the connection, the transfer of the data and the closing of the connection (and some extra actions).
This does not happen in one frame and requires a coroutine.
void Start() {
StartCoroutine(GetAudio(url));
}
private IEnumerator GetAudio(string url)
{
WWW www = new WWW("file://"+url);
yield return www;
if(string.IsNullOrEmpty(www.error) == false)
{
Debug.Log("Did not work");
yield break;
}
source = GetComponent<AudioSource>();
source.clip = www.GetAudioClip(false,true);
}
The WWW package got deprecated and Unity3D recommended using the UnityWebRequest package for API communications.
Try the following code snippet to download audio from a URL and play it using the AudioSource gameObject.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class DownloadAndPlay : MonoBehaviour
{
public AudioSource audioSource;
// Start is called before the first frame update
void Start()
{
string URL = "http://api.ispeech.org/api/rest?apikey=...&action=convert&voice=eurspanishfemale&text=hola+que+tal";
StartCoroutine(DownloadAudio(URL));
}
// Update is called once per frame
void Update()
{
}
IEnumerator DownloadAudio(string URL) {
using (UnityWebRequest www_audio = UnityWebRequestMultimedia.GetAudioClip(URL, AudioType.MPEG)) {
yield return www_audio.SendWebRequest();
if (www_audio.isNetworkError) {
Debug.Log(www_audio.error);
} else {
AudioClip clip = DownloadHandlerAudioClip.GetContent(www_audio);
audioSource.clip = clip;
audioSource.Play();
}
}
}
}
For more: https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequest.html

Frame Capture using Matrox Commands

I'm working on a project where I have to set the fps of a video stream (as 10) from a camera and grab a frame every 5th frame. I'm working on a program that has already been half written by someone else. The thing is, they have used Matrox Framegrabber dlls. There is also Matrox Frame Grabber on the device. But I cant find any commands for framegrab in C#. I found the following code for C++.
MIL_ID MdispAlloc(SystemId, DispNum, DispFormat, InitFlag,
DisplayIdPtr)
where
MIL_ID SystemId; System identifier
long DispNum; Display number
char *DispFormat; Display format name or file name
long InitFlag; Initialization flag
MIL_ID *DisplayIdPtr; Storage location for the display identifier
The above command allocates a display. Can someone please help me write the program in C#. Also, anyone with experience in Matrox dlls please give me an idea on how to approach frame capture and fps set up.
Thanks.
This is for everyone who is new to matrox framegrabber.
The first thing you should do is add matrox dll as reference. Be aware that there are currently two matrox versions out- Matrox 9 and Matrox 10.
Depending on version of matrox installed in user system dll should be added. (This can be checked by looking for "MIL_PATH" in system directories.
Then, declare some variables which will be used in matrox grabbing.
Some of mine are below:
public static MIL_ID MilApplication = MIL.M_NULL; // Application identifier.
public static MIL_ID MilSystem = MIL.M_NULL; // System identifier.
public static MIL_ID MilDisplay = MIL.M_NULL; // Display identifier.
public static MIL_ID MilDigitizer = MIL.M_NULL; // Digitizer identifier.
public static MIL_ID MilImage = MIL.M_NULL; // Image identifier.
public static MIL_ID MilRecord = MIL.M_NULL; // 8 bit Pointer only for Video Recording.
public MIL_INT MilINT = MIL.M_NULL;
public MIL_INT NbPixelsPtr = MIL.M_NULL;
MIL_ID MilImageDisp = MIL.M_NULL;
MIL_ID[] MilGrabBufferList = new MIL_ID[BUFFERING_SIZE_MAX];
Then run the following code
string MilSystemDet = "";
MilSystemDet = Environment.GetEnvironmentVariable("Mil_Path");
if (MilSystemDet != null)
{
string dcfFilePath = "";
FileDialog OpenFile = new OpenFileDialog();
OpenFile.Filter = "File Formats(*.dcf)|*.DCF;";
if (OpenFile.ShowDialog() == DialogResult.OK)
{
dcfFilePath = OpenFile.FileName;
MIL.MdigAlloc(MilSystem, MIL.M_DEFAULT, dcfFilePath, MIL.M_DEFAULT, ref MilDigitizer);
MIL.MbufAlloc2d(
MilSystem,
MIL.MdigInquire(MilDigitizer, MIL.M_SIZE_X, MIL.M_NULL),
MIL.MdigInquire(MilDigitizer, MIL.M_SIZE_Y, MIL.M_NULL),
8 + MIL.M_UNSIGNED,
MIL.M_IMAGE + MIL.M_DISP + MIL.M_GRAB,
ref MilImage);
MIL.MdispAlloc(MilSystem, MIL.M_DEFAULT, ("M_DEFAULT"), MIL.M_DEFAULT, ref MilDisplay);
MIL.MdigHalt(MilDigitizer);
}
}
When you want to start capture, run the following
MIL.MbufClear(MilImage, 0);
MIL.MdigGrabContinuous(MilDigitizer, MilImage);
MIL.MdispControl(MilDisplay, MIL.M_VIEW_MODE, MIL.M_AUTO_SCALE);
MIL.MdispControl(MilDisplay, MIL.M_SCALE_DISPLAY, MIL.M_ENABLE);
To copy current image into a buffer, use
MIL.MbufGet(MilImage, myBuffer);
where myBuffer is a ushort buffer with size equal to total number of pixels in image.
To save current image to a file, use
MIL.MbufSave(address,MilImage);
If you dont have a .dcf file you can get a default one from matrox installation cd for free. Or just install matrox viewer and in program files you can have one.
The image parameters such as width, height and bit depth are got from dcf file. But if you want, you can allocate them in Mbufalloc2d function above.
I'll try to check this answer periodically. If anyone has any questions ask me. Ill try to answer them to the best of my knowledge.
Seems like you have figured it out but for the ones that have not, all you need to do is include the MIL library and have MIL. before the function name in C++.
Like,
MbufClear(MilImageDisp[0], 0x0);
->
MIL.MbufClear(MilImage, 0);
Edit for your question on FPS setup: It's automatic based on your camera and DCF.

unity assetbundle loadasset type

I am having issue with the asset bundle from unity. I have a bundle with multiple assets in it with the same name, but different extension, like bonus.png bonus.prefab.
When I try to instanciate a prefab named bonus, the assetBundle.LoadAssets("bonus") function doesnt return me a gameobject like it usuallly do. This seems to be happening only if i have multiple asset with the same name.
AssetBundleRequest request = assetBundle.LoadAssetAsync(m_ObjectsToPool[i].m_Name, typeof(GameObject));
yield return request;
GameObject prefab = request.asset as GameObject;
if (prefab != null)
{
PoolManager.Instance.AddLoadedPrefabToPool(prefab, m_ObjectsToPool[i].m_Name, null, m_ObjectsToPool[i].m_Amount);
}
But if i call loadallassets(typeof(GameObject)) and then use a for loop, i can find my asset and instanciante it properly. but that is just a dirty way of doing it.
You should be able to load assets of different types with the same name.
What version of Unity are you using?
Your code above looks correct (except for the typo calling it LoadAssetAsync?), and we don't know for sure it is failing to enter the if() statement?
The following worked for me on Unity 4.5.5f1
Added ExportAssetBundles.cs context menu script to my Unity build from Unity Docs
Created something to export
found a JPG dragged it in and named it "marble.jpg"
created a cube, named it "marble" and dragged it into project to create a prefab
created a material, named it "marble", added the jpg and dragged it onto the cube, pressed apply.
Hilighted all 3 and exported asset bundle using "Build Assets From Selection - Track Selection" and saved it to "c:\temp\marble.unity3d"
Added a script to load that asset bundle on start (similiar to yours):
using UnityEngine;
using System.Collections;
public class BundleTest : MonoBehaviour {
void Start () {
StartCoroutine(StartCo());
}
IEnumerator StartCo() {
string url = "file://c:\\temp\\marble.unity3d";
WWW www = new WWW(url);
yield return www;
AssetBundle bundle = www.assetBundle;
AssetBundleRequest request = bundle.LoadAsync ("marble", typeof(GameObject));
yield return request;
Debug.Log ("loaded asset: " + request.asset.ToString());
GameObject prefab = request.asset as GameObject;
GameObject go = (GameObject)Instantiate(prefab);
bundle.Unload(false);
www.Dispose();
}
}
Ran Unity and verified I see the game object correctly.
It used to work when I was on unity 4.6, but I am now using the beta 5.0.17. And no its not a typo, it is really laodassetasync I have, I also tried with loadasset only with the same result. Right now I am using
var allAssets = assetBundle.LoadAllAssets(typeof(GameObject));
for (int i = 0; i < m_ObjectsToPool.Count; i++)
{
bool found = false;
for (int j = 0; j < allAssets.Length; j++)
{
if (allAssets[j].name == m_ObjectsToPool[i].m_Name)
{
PoolManager.Instance.AddLoadedPrefabToPool((GameObject)allAssets[j], m_ObjectsToPool[i].m_Name, null, m_ObjectsToPool[i].m_Amount);
found = true;
break;
}
}
if (!found)
{
Debug.Log(string.Format("{0} object could not be found in assetbundle", m_ObjectsToPool[i].m_Name));
}
}
and it is working, but i dont really like this way of doing it.
Having same issue with Unity 5.1, I've found this solution:
Besides refering asset by base name (no directory, no extension parts of path), you can also use full relative path (including file extension, relative to project root).
Let's say I've got bundle created from directory Assets/Bundle, it contains following files:
Prefabs/Box.prefab
Prefabs/Box2.prefab
Models/Box.fbx
Materials/Box.mat
Textures/Box.png
So the documented way of loading prefab that fails in our cases is
// May return nulll
bundle.LoadAsset<GameObject>("Box")
And this is the not documented way that's working correctly in our case
bundle.LoadAsset<GameObject>("assets/bundle/prefabs/box.prefab")
If you are not sure what is the correct asset name you should use for LoadAsset, you can use following code to list all asset names in bundle
string[] assets = bundle.GetAllAssetNames();
foreach (string asset in assets)
{
Debug.Log(asset);
}

Categories