we are trying to automatically capture an image from the webcam using MediaCapture class. We are trying to create an application which opens the camera, waits for a moment and captures the image in front of it without someone to tap the screen to capture. we tried using LowLagPhotoCapture class but does not work as desired. Sample code -
async private void InitMediaCapture()
{
MediaCapture _mediaCapture = new MediaCapture();
await _mediaCapture.InitializeAsync();
_displayRequest.RequestActive();
PreviewControlCheckIn.Source = _mediaCapture;
await _mediaCapture.StartPreviewAsync();
await Task.delay(500);
CaptureImage();
}
async private void CaptureImage()
{
storeFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync ("TestPhoto.jpg",CreationCollisionOption.GenerateUniqueName);
ImageEncodingProperties imgFormat = ImageEncodingProperties.CreateJpeg();
await _mediaCapture.CapturePhotoToStorageFileAsync(imgFormat, storeFile);
await _mediaCapture.StopPreviewAsync();
}
Any info would be great, thanks in advance for the help.
I have completed your provided code and achieved your requirement. Please refer to the following code. Please note that you should declare camera and the microphone capabilities in your Universal Windows Platform (UWP) app's package manifest to access certain API.
async private void InitMediaCapture()
{
_mediaCapture = new MediaCapture();
var cameraDevice = await FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel.Back);
var settings = new MediaCaptureInitializationSettings { VideoDeviceId = cameraDevice.Id };
await _mediaCapture.InitializeAsync(settings);
_displayRequest.RequestActive();
PreviewControl.Source = _mediaCapture;
await _mediaCapture.StartPreviewAsync();
var picturesLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures);
_captureFolder = picturesLibrary.SaveFolder ?? ApplicationData.Current.LocalFolder;
await Task.Delay(500);
CaptureImage();
}
async private void CaptureImage()
{
var storeFile = await _captureFolder.CreateFileAsync("PreviewFrame.jpg", CreationCollisionOption.GenerateUniqueName);
ImageEncodingProperties imgFormat = ImageEncodingProperties.CreateJpeg();
await _mediaCapture.CapturePhotoToStorageFileAsync(imgFormat, storeFile);
await _mediaCapture.StopPreviewAsync();
}
private static async Task<DeviceInformation> FindCameraDeviceByPanelAsync(Windows.Devices.Enumeration.Panel desiredPanel)
{
// Get available devices for capturing pictures
var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
// Get the desired camera by panel
DeviceInformation desiredDevice = allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredPanel);
// If there is no device mounted on the desired panel, return the first device found
return desiredDevice ?? allVideoDevices.FirstOrDefault();
}
The photo will be saved to Pictures library. And I have upload the code sample to github. Please check!
Related
I'm using media composition to preview videos and to generate streams. I pass a MediaEncoding Profile in which the video container I am assigning the bitrate has to apply when previewing. But it's not working. Here's the code:
MediaEncodingProfile profile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.HD720p);
profile.Video.Bitrate = 1000000; // Any Bitrate
var stream = VideoComposition.GenerateMediaStreamSource(profile);
videoPlayer.SetMediaStreamSource(stream);
By testing, there is no effect in the MediaStreamSource when we assign MediaEncodingProfile.Video.Bitrate in your scenario.
You could use Windows.Media.Transcoding APIs to transcode video files from one format to another to show the effect of assigning bitrate.
Please check the following code as a sample:
private MediaComposition VideoComposition;
private MediaStreamSource mediaStreamSource;
private StorageFile destination;
……
private async void button_Click(object sender, RoutedEventArgs e)
{
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
picker.FileTypeFilter.Add(".mp4");
Windows.Storage.StorageFile pickedFile = await picker.PickSingleFileAsync();
if (pickedFile == null)
{
return;
}
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
destination = await localFolder.CreateFileAsync("destination.mp4",CreationCollisionOption.ReplaceExisting);
MediaEncodingProfile profile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.HD720p);
MediaTranscoder transcoder = new MediaTranscoder();
profile.Video.Bitrate = 50000; // Any Bitrate
PrepareTranscodeResult prepareOp = await
transcoder.PrepareFileTranscodeAsync(pickedFile, destination, profile);
if (prepareOp.CanTranscode)
{
var transcodeOp = prepareOp.TranscodeAsync();
transcodeOp.Completed +=
new AsyncActionWithProgressCompletedHandler<double>(TranscodeComplete);
}
else
{
switch (prepareOp.FailureReason)
{
case TranscodeFailureReason.CodecNotFound:
System.Diagnostics.Debug.WriteLine("Codec not found.");
break;
case TranscodeFailureReason.InvalidProfile:
System.Diagnostics.Debug.WriteLine("Invalid profile.");
break;
default:
System.Diagnostics.Debug.WriteLine("Unknown failure.");
break;
}
}
}
private async void TranscodeComplete(IAsyncActionWithProgress<double> asyncInfo, AsyncStatus asyncStatus)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => {
var stream = await destination.OpenAsync(Windows.Storage.FileAccessMode.Read);
videoPlayer.SetSource(stream, destination.ContentType);
});
}
You could delete the destination file if you do not want to save the file.
I am trying to use the Windows.Graphics.Capture namespace to capture screenshot from a comaptible application.
I based my code on the official examples here: MS sample screenshot code
The code in question is the following:
private async void btnCapture_Click(object sender, EventArgs e)
{
process = Process.GetProcesses().Where(p => p.ProcessName == "xxxxxxxxxxx").Single();
hwnd = process.MainWindowHandle;
GraphicsCaptureItem item = CaptureHelper.CreateItemForWindow(hwnd);
device = Direct3D11Helper.CreateDevice();
capture = new BasicCapture(device, item);
framePool = Direct3D11CaptureFramePool.Create(device, DirectXPixelFormat.B8G8R8A8UIntNormalized, 1, item.Size);
session = framePool.CreateCaptureSession(item);
session.StartCapture();
using (frame = framePool.TryGetNextFrame())
{
var bmp = await SoftwareBitmap.CreateCopyFromSurfaceAsync(frame.Surface);
StorageFolder pictureFolder = KnownFolders.CameraRoll;
StorageFile file = await pictureFolder.CreateFileAsync("test.png", CreationCollisionOption.ReplaceExisting);
using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, fileStream);
encoder.SetSoftwareBitmap(bmp);
await encoder.FlushAsync();
}
}
}
If i put a breakpoint in line using (frame = framePool.TryGetNextFrame()) the frame is populated and the file is saved normally by the code that follows.
If i just run the app then frame is null and an error occurs. I cant use await on the framePool.TryGetNextFrame()
I feel that this is a Frankenstein code as i am learning the new capturing paradigm. Any help how to make this code work?
Eventually i will need this code to work with a timer taking screenshots at a regular interval.
Direct3D11CaptureFramePool has a FrameArrived event, which you could listen for before trying to get the frame:
var cts = new TaskCompletionSource<object>();
framePool.FrameArrived += (s, e) => cts.SetResult(null);
session.StartCapture();
await cts.Task;
// Frame should now be available
using (frame = framePool.TryGetNextFrame())
I want to open multiple audio files in UWP using the FileOpenPicker but I am getting an error that I cant Cannot Convert. How can I fix this?
And if this is fixed, will all the audio files play in order or all at the same time?
public MainPage()
{
this.InitializeComponent();
}
MediaSource media_source;
MediaPlayer media_player;
public async System.Threading.Tasks.Task OpenfileAsync()
{
var filePicker = new Windows.Storage.Pickers.FileOpenPicker();
filePicker.FileTypeFilter.Add(".mp3");
filePicker.FileTypeFilter.Add(".mp4");
filePicker.FileTypeFilter.Add(".ogg");
filePicker.FileTypeFilter.Add(".wav");
filePicker.FileTypeFilter.Add(".wma");
filePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.MusicLibrary;
StorageFile file = await filePicker.PickSingleFileAsync();
if (file != null)
{
media_source = MediaSource.CreateFromStorageFile(file);
media_player = new MediaPlayer();
media_player.Source = media_source;
mediaPlayerElement.SetMediaPlayer(media_player);
media_player.Play();
}
}
private async void Select_track_Click(object sender, RoutedEventArgs e)
{
await OpenfileAsync();
}
public async System.Threading.Tasks.Task OpenMultipleAsync()
{
var filePicker = new Windows.Storage.Pickers.FileOpenPicker();
filePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.MusicLibrary;
filePicker.FileTypeFilter.Add(".mp3");
filePicker.FileTypeFilter.Add(".mp4");
filePicker.FileTypeFilter.Add(".ogg");
filePicker.FileTypeFilter.Add(".wav");
filePicker.FileTypeFilter.Add(".wma");
filePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.MusicLibrary;
StorageFile file = await filePicker.PickMultipleFilesAsync();
if (file != null)
{
media_source = MediaSource.CreateFromStorageFile(file);
media_player = new MediaPlayer();
media_player.Source = media_source;
mediaPlayerElement.SetMediaPlayer(media_player);
media_player.Play();
}
}
private async void playlist_Click(object sender, RoutedEventArgs e)
{
await OpenMultipleAsync();
}
I am getting the error at StorageFile file = await filepicker.PickmultiplefilesAsync();
The FileOpenPicker.PickMultipleFilesAsync method has the following signature:
IAsyncOperation<IReadOnlyList<StorageFile>> PickMultipleFilesAsync()
In contrast to PickFileAsync it returns a IReadOnlyList<StorageFile>, so you will actually get a list of multiple files the user selected. You should update the code like this:
var files = await filePicker.PickMultipleFilesAsync();
foreach (var file in files)
{
if (file != null)
{
media_source = MediaSource.CreateFromStorageFile(file);
media_player = new MediaPlayer();
media_player.Source = media_source;
mediaPlayerElement.SetMediaPlayer(media_player);
media_player.Play();
}
}
This solution will play all the sounds at once. For one by one playback you can use #touseefbsb solution :-) .
for playing a list of files its best that you use MediaPlaybackList
Also you only need to set the SuggestedStartLocation once, and when you use PickMultipleFilesAsync() you get a List of files returned so you need that iterate through that list to get all files and add them to your MediaPlaybackList
Modify your OpenMultipleAsync method like this :
public async System.Threading.Tasks.Task OpenMultipleAsync()
{
var filePicker = new Windows.Storage.Pickers.FileOpenPicker();
filePicker.FileTypeFilter.Add(".mp3");
filePicker.FileTypeFilter.Add(".mp4");
filePicker.FileTypeFilter.Add(".ogg");
filePicker.FileTypeFilter.Add(".wav");
filePicker.FileTypeFilter.Add(".wma");
filePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.MusicLibrary;
_mediaPlaybackList = new MediaPlaybackList();
var files = await filePicker.PickMultipleFilesAsync();
foreach (var file in files)
{
var mediaPlaybackItem = new MediaPlaybackItem(MediaSource.CreateFromStorageFile(file));
_mediaPlaybackList.Items.Add(mediaPlaybackItem);
}
_mediaPlayer = new MediaPlayer();
_mediaPlayer.Source = _mediaPlaybackList;
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);
}
More details about MediaPlaybackItem can be seen here
and to answer 'will these media files play together at the same time or one after the other' : they will play one after the other in a row, that is the purpose if MediaPlaybackList, it supports gapless playback for playlists.
I am trying to develop a UWP app where I need to record video via webcam. I have followed microsoft tutorial about it here but the problem is I am getting following error again and again and recording does not work.
Error
"This object needs to be initialized before the requested operation
can be carried out.\r\nThis object needs to be initialized before the
requested operation can be carried out."
Here is my code:
int counter = 1;
var myVideos = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Videos);
StorageFile file = await myVideos.SaveFolder.CreateFileAsync("survillance "+DateTime.Now.ToString("dd-MM-yyyy")+"_"+counter+".wmv", CreationCollisionOption.GenerateUniqueName);
try
{
MediaEncodingProfile recordProfile = null;
recordProfile = MediaEncodingProfile.CreateWmv(VideoEncodingQuality.Auto);
_mediaRecording = await _mediaCapture.PrepareLowLagRecordToStorageFileAsync(recordProfile,file);
await _mediaRecording.StartAsync();
status.Text = "Video recording in progress...";
}
catch (Exception ex)
{
status.Text = "Failed to Capture...";
var msg = new MessageDialog(ex.Message, "Capturing Error").ShowAsync();
}
Please help me in figuring out the problem. Thanks
You forgot to call MediaCapture.InitializeAsync() before starting the capture.
MediaEncodingProfile recordProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto);
_mediaCapture = new MediaCapture();
_mediaCapture.InitializeAsync();
_mediaRecording = await _mediaCapture.PrepareLowLagRecordToStorageFileAsync(recordProfile,file);
await _mediaRecording.StartAsync();
I can successfully play sounds using Xamarin forms (Android and iOS) however I also need to achieve the following:
I need to await so that if multiple sounds are 'played', one will complete before the next.
I need to return a boolean to indicate whether operation was a success.
Here is my current simplified code (for the iOS platform):
public Task<bool> PlayAudioTask(string fileName)
{
var tcs = new TaskCompletionSource<bool>();
string filePath = NSBundle.MainBundle.PathForResource(
Path.GetFileNameWithoutExtension(fileName), Path.GetExtension(fileName));
var url = NSUrl.FromString(filePath);
var _player = AVAudioPlayer.FromUrl(url);
_player.FinishedPlaying += (object sender, AVStatusEventArgs e) =>
{
_player = null;
tcs.SetResult(true);
};
_player.Play();
return tcs.Task;
}
To test the method, I have tried calling it like so:
var res1 = await _audioService.PlayAudioTask("file1");
var res2 = await _audioService.PlayAudioTask("file2");
var res3 = await _audioService.PlayAudioTask("file3");
I had hoped to hear the audio for file1, then file2, then file3. However I only hear file 1 and the code doesn't seem to reach the second await.
Thankyou
I think your issue here is that the AVAudioPlayer _player was being cleared out before it was finished. If you were to add debugging to your FinsihedPlaying, you'll notice that you never hit that point.
Try these changes out, I made a private AVAudioPlayer to sit outside of the Task
(I used the following guide as a reference https://developer.xamarin.com/recipes/ios/media/sound/avaudioplayer/)
public async void play()
{
System.Diagnostics.Debug.WriteLine("Play 1");
await PlayAudioTask("wave2.wav");
System.Diagnostics.Debug.WriteLine("Play 2");
await PlayAudioTask("wave2.wav");
System.Diagnostics.Debug.WriteLine("Play 3");
await PlayAudioTask("wave2.wav");
}
private AVAudioPlayer player; // Leave the player outside the Task
public Task<bool> PlayAudioTask(string fileName)
{
var tcs = new TaskCompletionSource<bool>();
// Any existing sound playing?
if (player != null)
{
//Stop and dispose of any sound
player.Stop();
player.Dispose();
}
string filePath = NSBundle.MainBundle.PathForResource(
Path.GetFileNameWithoutExtension(fileName), Path.GetExtension(fileName));
var url = NSUrl.FromString(filePath);
player = AVAudioPlayer.FromUrl(url);
player.FinishedPlaying += (object sender, AVStatusEventArgs e) =>
{
System.Diagnostics.Debug.WriteLine("DONE PLAYING");
player = null;
tcs.SetResult(true);
};
player.NumberOfLoops = 0;
System.Diagnostics.Debug.WriteLine("Start Playing");
player.Play();
return tcs.Task;
}