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
Related
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.
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.
I previously made a post asking how to send a .3gpp audio file up to the parse cloud here:
Xamarin C# Android - converting .3gpp audio to bytes & sending to parseObject
I have managed to do this successfully, on parse's data manager, I can click the file's link and play the sound sent from my android device successfully.
Here's the code for uploading the data to the cloud:
async Task sendToCloud(string filename)
{
ParseClient.Initialize ("Censored Key", "Censored Key");
string LoadPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData);
string savetheFile = sName + ".3gpp";
string tempUserName;
LoadPath += savetheFile;
Console.WriteLine ("loadPath: " + LoadPath);
try
{
byte[] data = File.ReadAllBytes(LoadPath);
ParseFile file = new ParseFile(savetheFile, data);
await file.SaveAsync();
var auidoParseObject = new ParseObject("AudioWithData");
//Console.WriteLine(ParseUser.getUserName());
if (ParseUser.CurrentUser != null)
{
tempUserName = ParseUser.CurrentUser.Username.ToString();
}
else{
tempUserName = "Anonymous";
}
//tempUserName = ParseUser.CurrentUser.Username.ToString();
Console.WriteLine("PARSE USERNAME: " + tempUserName);
auidoParseObject["userName"] = tempUserName;
auidoParseObject["userName"] = tempUserName;
auidoParseObject["file"] = file;
await auidoParseObject.SaveAsync();
}
catch (Exception e)
{
Console.WriteLine("Failed to await audio object! {0}" + e);
}
}
So as you can see, I'm sending a ParseObject called "AudioWithData".
This object contains two children:
-The username of the user who uploaded the file (string)
-The parseFile called "file" (which has the following two children)
---SaveTheFile (A string containing the name of the audio file, input by the user, with the .3gpp extension added on the end, for example "myAudioFile.3gpp"
---data (this contains the bytes of the audio file)
I need to be able to download the file onto my android device, and play it through a mediaplayer object.
I've checked over the documentation on the parse website, but I haven't managed to do this:
(excuse my pseudo querying syntax here)
SELECT (audio files) FROM (the parseObject) WHERE (the username = current user)
I then, eventually, want to place all of these files into a listview, and when the user clicks the file, it plays the audio.
I've tried the following but I don't really know what I'm doing with it...
async Task RetrieveSound(string filename)
{
ParseClient.Initialize ("Censored key", "Censored key");
Console.WriteLine ("Hit RetrieveSound, filename = " + filename);
string username;
var auidoParseObject = new ParseObject("AudioWithData");
if (ParseUser.CurrentUser != null) {
username = ParseUser.CurrentUser.Username.ToString ();
} else {
username = "Anonymous";
}
string cloudFileName;
Console.WriteLine ("username set to: " + username);
var HoldThefile = auidoParseObject.Get<ParseFile>("audio");
//fgher
var query = from audioParseObject in ParseObject.GetQuery("userName")
where audioParseObject.Get<String>("userName") == username
select file;
IEnumerable<ParseFile> results = await query.FindAsync();
Console.WriteLine ("passed the query");
//wfojh
byte[] data = await new HttpClient().GetByteArrayAsync(results.Url);
Console.WriteLine ("putting in player...");
_player.SetDataSourceAsync (data);
_player.Prepare;
_player.Start ();
}
Any help would be GREATLY APPRECIATED! Even a point in the right direction would be great!
Thanks!
EDIT--
I'm actually getting a query error on the following lines
(I can't post images because of my reputation - I lost access to my main stackOverflow account :/ )
Links to images here:
first error: http://i.stack.imgur.com/PZBJr.png
second error: http://i.stack.imgur.com/UkHvX.png
Any ideas? The parse documentation is vague about this.
this line will return a collection of results
IEnumerable<ParseFile> results = await query.FindAsync();
you either need to iterate through them with foreach, or just pick the first one
// for testing, just pick the first one
if (results.Count > 0) {
var result = results[0];
byte[] data = await new HttpClient().GetByteArrayAsync(result.Url);
File.WriteAllBytes(some_path_to_a_temp_file, data);
// at this point, you can just initialize your player with the audio file path and play as normal
}
I have an image in IsolatedStorage, and I would like to programmatically set it as the device lock screen background. My problem is that I cannot get the correct path required by LockScreen.SetImageUri. From referencing http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj206968(v=vs.105).aspx it is evident that `"ms-appdata:///local/" is the required precursor for local images.
var schema = isAppResource ? "ms-appx:///" : "ms-appdata:///Local/";
var uri = new Uri(schema + filePathOfTheImage, UriKind.Absolute);
I have created a folder in my applications IsolatedStorage called Pictures in which jpg images are saved from the CameraCaptureTask. I have tried several ways to access images within this folder via the above scheme but I always receive an ArgumentException on the next line
Windows.Phone.System.UserProfile.LockScreen.SetImageUri(uri);
When debugging, however, I see that uri = "ms-appdata:///Local/Pictures/WP_20130812_001.jpg", how is this not correct?
My implementation is as follows
private void recent_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
capturedPicture = (sender as LongListSelector).SelectedItem as CapturedPicture;
if (capturedPicture != null)
{
//filename is the name of the image in the IsolatedStorage folder named Pictures
fileName = capturedPicture.FileName;
}
}
void setAsLockScreenMenuItem_Click(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(fileName))
{
//PictureRepository.IsolatedStoragePath is a string = "Pictures"
//LockHelper("isostore:/" + PictureRepository.IsolatedStoragePath + "/" + fileName, false); //results in FileNotFoundException
LockHelper(PictureRepository.IsolatedStoragePath + "/" + fileName, false); //results in ArgumentException
}
else
{
MessageBoxResult result = MessageBox.Show("You must select an image to set it as your lock screen.", "Notice", MessageBoxButton.OK);
if (result == MessageBoxResult.OK)
{
return;
}
}
}
private async void LockHelper(string filePathOfTheImage, bool isAppResource)
{
try
{
var isProvider = Windows.Phone.System.UserProfile.LockScreenManager.IsProvidedByCurrentApplication;
if (!isProvider)
{
// If you're not the provider, this call will prompt the user for permission.
// Calling RequestAccessAsync from a background agent is not allowed.
var op = await Windows.Phone.System.UserProfile.LockScreenManager.RequestAccessAsync();
// Only do further work if the access was granted.
isProvider = op == Windows.Phone.System.UserProfile.LockScreenRequestResult.Granted;
}
if (isProvider)
{
// At this stage, the app is the active lock screen background provider.
// The following code example shows the new URI schema.
// ms-appdata points to the root of the local app data folder.
// ms-appx points to the Local app install folder, to reference resources bundled in the XAP package.
var schema = isAppResource ? "ms-appx:///" : "ms-appdata:///Local/";
var uri = new Uri(schema + filePathOfTheImage, UriKind.Absolute);
// Set the lock screen background image.
Windows.Phone.System.UserProfile.LockScreen.SetImageUri(uri);
// Get the URI of the lock screen background image.
var currentImage = Windows.Phone.System.UserProfile.LockScreen.GetImageUri();
System.Diagnostics.Debug.WriteLine("The new lock screen background image is set to {0}", currentImage.ToString());
}
else
{
MessageBox.Show("You said no, so I can't update your background.");
}
}
catch (System.Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
}
How might I modify LockScreen.SetImageUri to the proper expected uri?
For setting lock screen images from the app, you might want to declare your app as lock screen provider. You can do that by modifying the WMAppManifest.xml file by adding the following tag:
<Extensions>
<Extension ExtensionName="LockScreen_Background" ConsumerID="{111DFF24-AA15-4A96-8006-2BFF8122084F}" TaskID="_default" />
</Extensions>
Check to see if you have this tag in your manifest file.
I hope this could help you to address your issue.
If your app is already installed, make sure that it is an background image provider. If not then go to settings -> lock screen -> background and select your application from the list.
On the programmatic side:
1. Declare the app’s intent in the application manifest file
Edit WMAppManifest.xml with the XML editor, make sure the following extension is present:
<Extensions> <Extension ExtensionName="LockScreen_Background" ConsumerID="{111DFF24-AA15-4A96-8006-2BFF8122084F}" TaskID="_default" /> </Extensions>
2. Write code to change the background image
The following is an example of how you can write the code for setting the background.
private async void lockHelper(Uri backgroundImageUri, string backgroundAction)
{
try
{
//If you're not the provider, this call will prompt the user for permission.
//Calling RequestAccessAsync from a background agent is not allowed.
var op = await LockScreenManager.RequestAccessAsync();
//Check the status to make sure we were given permission.
bool isProvider = LockScreenManager.IsProvidedByCurrentApplication; if (isProvider)
{
//Do the update.
Windows.Phone.System.UserProfile.LockScreen.SetImageUri(backgroundImageUri);
System.Diagnostics.Debug.WriteLine("New current image set to {0}", backgroundImageUri.ToString());
}
else { MessageBox.Show("You said no, so I can't update your background."); }
}
catch (System.Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); }
}
Regarding Uris, there are many options, but keep on mind:
To use an image that you shipped in your app, use ms-appx:///
Uri imageUri = new Uri("ms-appx:///background1.png", UriKind.RelativeOrAbsolute); LockScreen.SetImageUri(imageUri);
To use an image stored in the Local Folder, use ms-appdata:///local/shared/shellcontent
Must be in or below the /shared/shellcontent subfolder
Uri imageUri = new Uri("ms-appdata:///local/shared/shellcontent/background2.png", UriKind.RelativeOrAbsolute); LockScreen.SetImageUri(imageUri);
any one can help me with a c# code to grab frames from a video file,
I am working on a live streaming server on (Asp.Net & c#)..
so when a user uploads his files after live streaming, at the point I have to capture a video frame, so that it can be listed
in the format of a you-tube video list...
thanks
Take a look at AForge.NET - it is a mature set of libraries for processing images and video.
You should be try this it works nice:
private Capture capture = null;
private void btnStart_Click(object sender, System.EventArgs e)
{
try
{
if ( capture == null )
throw new ApplicationException( "Please select a video and/or audio device." );
if ( !capture.Cued )
capture.Filename = txtFilename.Text;
capture.Start();
btnCue.Enabled = false;
btnStart.Enabled = false;
}
catch (Exception ex)
{
MessageBox.Show( ex.Message + "\n\n" + ex.ToString() );
}
}