Android Unity3D VideoPlayer Playing video "from URL" not working properly - c#

Platform: Unity 2020.1.0f1
I have a weird problem while creating a little game that is meant to download videos from a remote URL to Application.PersistentDataPath and play them in the Unity3D-VideoPlayer using the "RenderTexture"-way by pressing a button for a specific video.
In the editor EVERYTHING works fine...
On IOS EVERYTHING works fine...
On Android (no matter which version) only the video from the asset folder is played properly. Accessing a downloaded file from Application.persistentDataPath is simply showing nothing on Android...
Things I checked (in addition to simple blindness):
"External Write Permission" > forced everything on "internal"... not working
Using Path.Combine() and/or "string filepath = ..."
"Different Video Formats" > nope... the asset video is playing properly without transcoding (it is h.264 AVC, 650x650px, 30fps - AAC Audio, 44,1kHz, Bps 32)
Sample code below, the test scene can also be downloaded here:
http://weristaxel.de/upload/Videotest.unity
http://weristaxel.de/upload/VideotestController.cs
Video in Unity asset folder:
https://corolympics.azurewebsites.net/assets/game1howto.mov
What am I missing?
public void PlayFromPersistent()
{
// NOT WORKING ON ANDROID
VideoPlayer VideoHowTo = VideotestCanvas.transform.Find("VideoPlayer").GetComponent<VideoPlayer>();
string filePath = Application.persistentDataPath + "/game2howto.mov";
VideoHowTo.Stop();
VideoHowTo.url = filePath;
VideoHowTo.source = VideoSource.Url;
DebugText.text = "VideoHowTo.url = " + filePath;
VideoHowTo.Prepare();
VideoHowTo.Play();
}
public void PlayFromAssets()
{
// WORKING ON ANDROID
VideoPlayer VideoHowTo = VideotestCanvas.transform.Find("VideoPlayer").GetComponent<VideoPlayer>();
VideoHowTo.Stop();
VideoHowTo.clip = assetVideo;
VideoHowTo.source = VideoSource.VideoClip;
DebugText.text = "VideoHowTo.clip set - original path " + assetVideo.originalPath;
VideoHowTo.Play();
}
public void DownloadVideo()
{
// THIS DOWNLOADS A TEST VIDEO TO "persistentDataPath"...
string url = "https://corolympics.azurewebsites.net/assets/game2howto.mov";
Debug.Log("Downloading " + url);
var uwr = new UnityWebRequest(url, UnityWebRequest.kHttpVerbGET);
string filename = url.Split('/').Last();
string path = Path.Combine(Application.persistentDataPath , filename);
uwr.downloadHandler = new DownloadHandlerFile(path);
uwr.SendWebRequest();
DebugText.text = "Download to " + path + " finished";
}
public void AddListener()
{
// NOT WORKING ON ANDROID - THIS ADDS A LISTENER TO AN EMPTY BUTTON TO EMULATE THE TARGET BEHAVIOUR
Button button = VideotestCanvas.transform.Find("FromPersistentListenerButton").GetComponent<Button>();
Color blueColor = new Color32(52, 152, 219, 255);
button.GetComponent<Image>().color = blueColor;
button.onClick.AddListener(() =>
{
VideoPlayer VideoHowTo = VideotestCanvas.transform.Find("VideoPlayer").GetComponent<VideoPlayer>();
string filePath = Application.persistentDataPath + "/game2howto.mov";
VideoHowTo.Stop();
VideoHowTo.url = filePath;
VideoHowTo.source = VideoSource.Url;
DebugText.text = "VideoHowTo.url = " + filePath;
VideoHowTo.Play();
});
}

If you're still stuck i would try creating an independant function for when you add the listener event. So it would be something like 'button.onClick.AddListener(() => IndFunction())' instead of creating a new instance each time. I was stuck on something similar a while back and i created an editable script for each button to store the info for each one and set each according to a list of image links and image names.

Related

Unity, MacOS, cannot load audio from StreamingAssets using www.SendWebRequest()

I am working on an app targeting Windows, built in Unity.
All the audio files are in streamingAssets so the client can replace them and customize the app.
I have the following code loading the audio files into Audio Sources and it's working fine on Windows.
void SetAudioFromStreamingAssets()
{
if (string.IsNullOrEmpty(StreamingAssetFilePath)) return;
string fullpath = Application.streamingAssetsPath + "/" + StreamingAssetFilePath;
if (!File.Exists(fullpath)) return;
StartCoroutine(SetAudioClipFromFile(source,fullpath));
}
IEnumerator SetAudioClipFromFile(AudioSource audioSource, string path)
{
using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(path, AudioType.UNKNOWN))
{
yield return www.SendWebRequest();
if (www.isNetworkError)
{
VisDebug.AppendTxt("ERROR. Could not load music file: " + www.error, true);
}
else
{
AudioClip myClip = DownloadHandlerAudioClip.GetContent(www);
audioSource.clip = myClip;
}
}
}
A colleage of mine is trying to work on the project but he only has a mac. And the audio is not loading on his mac.
The code is reaching this line..
VisDebug.AppendTxt("ERROR. Could not load music file: " + www.error, true);
So File.Exists is true, and also www.isNetworkError is true.
and the www.error is...
Cannot connect to destination host
EDIT
The answer below is correct and just fyi here is an example of what the path needs to look like on macos.
file:///Users/spoopy/Documents/GitHub/Thing/Assets/StreamingAssets/GameLoad.wav
You have to prefix your path with file:// on MacOS and Linux.
You could put something like this after your variable definition.
#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
fullpath ="file://" + path);
#endif
Source

CrossMedia Plugin Only Opens Picture mode instead of Video

I have a button in my xamarin application where I want to be able to record a video. The only problem is that when I click on it, it takes the camera instead of video (see photo).
This is the method I am currently using.
private async Task TakeVideoAndSave()
{
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakeVideoSupported)
{
await DisplayAlert("No Camera", "No camera avaialble.", "OK");
return;
}
var createdInAppOn = _declaration.CreatedInAppOn.Value.ToString("s").Replace(":", string.Empty);
var path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var videoPath = Path.Combine(path, createdInAppOn + ".mp4");
var file = await CrossMedia.Current.TakeVideoAsync(new Plugin.Media.Abstractions.StoreVideoOptions
{
Name = createdInAppOn + ".mp4",
Quality = VideoQuality.Low,
});
if (file == null)
return;
await DisplayAlert("Video Recorded", "Location: " + file.Path, "OK");
file.Dispose();
}
How do I manage to get the video camera from android instead of the photo camera?
Thanks in advance
The MediaPicker class lets a user pick or take a photo or video on the device.
You can use CaptureVideoAsync which Opens the camera to take a video.
Here is the API documentation of MediaPicker:https://learn.microsoft.com/en-us/dotnet/api/xamarin.essentials.mediapicker?view=xamarin-essentials

How to save screenshot from Unity to azure storage?

I am working on a unity project and I need to save a certain screenshot from my game to a container in azure storage.
I already configured my azure account and created the container.
I managed to take the screenshot and save it in a directory on my computer but whenever I try to save it to my storage I cant because it does not found it. I go to that directory and I can see the screenshot.
This is how I do the screenshot part:
public void TappedCaptureScreenshot()
{
string filename = string.Format("{0}.png", DateTime.UtcNow.ToString("yy-MM-dd-HH-mm-ss-ff"));
Debug.Log("aca estoy 0 " + filename);
localPath = Screenshot.Capture(filename);
Debug.Log("local path " + localPath);
isCaptured = true;
//label.text = "Capture as: " + localPath;
}
This is how I save the picture:
public void TappedSave()
{
byte[] imageBytes = File.ReadAllBytes(localPath);
PutImage(imageBytes);
}
private void PutImage(byte[] imageBytes)
{
string filename = Path.GetFileName(localPath);
Debug.Log("Aca estoy 2 " + filename);
//label.text = "Put " + filename;
StartCoroutine(blobService.PutImageBlob(PutImageCompleted, imageBytes, container, filename, "image/png"));
}
Then whenever I clic a certain button, both functions are called.
This is the error I get:
FileNotFoundException: Could not find file "C:..\20-02-23-21-12-59-06.png"
I think the error has something to do with image bytes but I do not know why. Any suggestions?

WPF C# How to play local .swf file with a Control that still reacts to flow?

I'm trying to play a .swf file saved in the output folder, but the standard WebBrowser doesn't react to the flow of the document. It doesn't get cut off when it reaches the top of a Scrollviewer and that's a problem. I tried CefSharp, but I can only figure out how to play .swf files from the web. Are there any Controls that can play local .swf files and react with the flow.
EDIT:
Here's the code I used with CefSharp to load the .swf files. Basically, it loads a blank HTML file and then runs some JavaScript on it to create the correct Flash object with the correct path. This works for websites, but I need to run a local .swf file and that won't work (probably because CefSharp runs on Chromium and therefore has certain security settings that don't allow files from the computer to be accessed like that.)
if (TotalChecklistBrowser[itemNum].IsBrowserInitialized)
{
TotalChecklistBrowser[itemNum].Load(#"blank.html");
TotalChecklistBrowser[itemNum].FrameLoadEnd += (origin, args) =>
{
if (args.Frame.IsMain)
{
args.Frame.ExecuteJavaScriptAsync("document.body.innerHTML = \"\"; document.documentElement.style.overflow = \"hidden\"; document.body.style.margin = \"0\"; var obj = document.createElement(\"object\"); obj.width = \"260\"; obj.height = \"180\"; var param = document.createElement(\"param\"); param.id = \"item01\"; param.name = \"movie\"; param.value = \"" + BrowserTitles[itemNum].Replace(#"\", "/") + "\"; var embed = document.createElement(\"embed\"); embed.id = \"item02\"; embed.src = \"" + BrowserTitles[itemNum].Replace(#"\", "/") + "\"; embed.width = \"260\"; embed.height = \"180\"; document.body.appendChild(obj); obj.appendChild(param); obj.appendChild(embed); ");
}
};
}

Closed Captions resolving error System.UnauthorizedAccessException

So, I'm trying to implement closed captions support to my UWP video player (using MediaElement), I've followed this example to do so.
I'm getting an error when resolving it called "Error resolving track due to error NetworkError System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))"
I do it like this: I open a file using filepicker and then get the SRT of the video that was picked. After that I show it. Unfortunately, nothing appears.
Here is my OpenButton function:
private async void BtnOpenMedia_Click(object sender, RoutedEventArgs e)
{
FileOpenPicker filePicker = new FileOpenPicker();
filePicker.ViewMode = PickerViewMode.Thumbnail;
filePicker.SuggestedStartLocation = PickerLocationId.VideosLibrary;
filePicker.FileTypeFilter.Add(".mp4");
filePicker.FileTypeFilter.Add(".wmv");
filePicker.FileTypeFilter.Add(".mpg");
filePicker.FileTypeFilter.Add(".mpeg");
filePicker.FileTypeFilter.Add("*");
StorageFile storageFile = await filePicker.PickSingleFileAsync();
if (storageFile != null && mElement != null)
{
string strSource = Path.GetDirectoryName(storageFile.Path) + #"\" + storageFile.DisplayName + ".srt";
var mediaSource = MediaSource.CreateFromStorageFile(storageFile);
var ttsStream = TimedTextSource.CreateFromUri(new Uri(strSource));
ttsStream.Resolved += TtsStream_Resolved;
mediaSource.ExternalTimedTextSources.Add(ttsStream);
var mediaPlayback = new MediaPlaybackItem(mediaSource);
mElement.SetPlaybackSource(mediaPlayback);
}
}
Here is my resolve function:
private void TtsStream_Resolved(TimedTextSource sender, TimedTextSourceResolveResultEventArgs args)
{
if (args.Error != null)
{
var ignoreAwaitWarning = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
var msg = new MessageDialog("Error resolving track " + " due to error " + args.Error.ErrorCode + " " + args.Error.ExtendedError);
await msg.ShowAsync();
});
return;
}
}
P.S: Also, I don't know if this is duplicated or not, that's why I'm adding it in this but I've done my research and found nothing. How to preview frames of MediaElement ? For example like YouTube you can preview thumbnails in the slider, I don't know how to achieve that, thanks!
You used a FileOpenPicker to select the Video file, but use a Path to access the .srt file. The .srt file is also in the Video file's folder. I reproduced your problem here:
The error message is clear, you have no access to this file, this file indicates the .srt file, so the problem is where did you store this .srt file. Just have a test, seems TimedTextSource.CreateFromUri(Uri) | createFromUri(Uri) method does not support to access the files in the local machine, but you can use TimedTextSource.CreateFromStream(IRandomAccessStream) | createFromStream(IRandomAccessStream) method for example like this:
if (storageFile != null && mElement != null)
{
//string strSource = Path.GetDirectoryName(storageFile.Path) + #"\" + storageFile.DisplayName + ".srt";
var fileSource = await KnownFolders.VideosLibrary.GetFileAsync(storageFile.DisplayName + ".srt");
IRandomAccessStream strSource = await fileSource.OpenReadAsync();
var mediaSource = MediaSource.CreateFromStorageFile(storageFile);
//var ttsStream = TimedTextSource.CreateFromUri(new Uri(strSource));
var ttsStream = TimedTextSource.CreateFromStream(strSource);
ttsStream.Resolved += TtsStream_Resolved;
mediaSource.ExternalTimedTextSources.Add(ttsStream);
var mediaPlayback = new MediaPlaybackItem(mediaSource);
mediaPlayback.TimedMetadataTracksChanged += (sender1, args) =>
{
mediaPlayback.TimedMetadataTracks.SetPresentationMode(0, TimedMetadataTrackPresentationMode.PlatformPresented);
};
mElement.SetPlaybackSource(mediaPlayback);
}
When using this code, the .srt file and video file should in the Video lib and the capability "Videos Library" should be enabled in the manifest.
In an UWP app, you can only access the files in known folder like picture lib, music lib and video lib and doc lib or local folder of your app, if your video is not in these folders, you should also handle the exception when access is denied in this scenario.
How to preview frames of MediaElement ? For example like YouTube you can preview thumbnails in the slider.
For this question, I can't find any ready-made sample for you, but I think the scenario 4 of official Media editing sample can be a direction, it shows a overlay layer on MediaElement, maybe you can set the "baseVideoFile" and the "overlayVideoFile" with the same source. The problem is when and where to show this overlay layer, it's related to the transport control of MediaElement. This is for now just a mind, you can have a try.

Categories