I am creating a Windows Universal application. I want to the user to be able to upload a picture and the user should have the option of taking one on the spot and sending that. I have this working using the MediaCapture api. However I can only seem to use one camera, so for example if my phone has a front and a back camera only the front camera is used. How would I be able to switch the camera that is in use?
I had read something somewhere about using something like this:
private static async Task<DeviceInformation> GetCameraID(Windows.Devices.Enumeration.Panel desired)
{
DeviceInformation deviceID = (await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture))
.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desired);
return deviceID;
}
However this always returns null for me, since the deviceID is always null.
Alternatively is there the option of giving control to an application that takes the picture and returns the taken picture to my application? I have found the following, but it doesn't work for Windows Universal apps:
http://msdn.microsoft.com/en-us/library/windows/apps/hh394006(v=vs.105).aspx
Here is how I would do it:
First the initialization part
// First need to find all webcams
DeviceInformationCollection webcamList = await DeviceInformation.FindAllAsync(DeviceClass.All)
// Then I do a query to find the front webcam
DeviceInformation frontWebcam = (from webcam in webcamList
where webcam.EnclosureLocation != null
&& webcam.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Front
select webcam).FirstOrDefault();
// Same for the back webcam
DeviceInformation backWebcam = (from webcam in webcamList
where webcam.EnclosureLocation != null
&& webcam.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back
select webcam).FirstOrDefault();
// Then you need to initialize your MediaCapture
newCapture = new MediaCapture();
await newCapture.InitializeAsync(new MediaCaptureInitializationSettings
{
// Choose the webcam you want
VideoDeviceId = backWebcam.Id,
AudioDeviceId = "",
StreamingCaptureMode = StreamingCaptureMode.Video,
PhotoCaptureSource = PhotoCaptureSource.VideoPreview
});
// Set the source of the CaptureElement to your MediaCapture
// (In my XAML I called the CaptureElement *Capture*)
Capture.Source = newCapture;
// Start the preview
await newCapture.StartPreviewAsync();
Secondly take the picture
//Set the path of the picture you are going to take
StorageFolder folder = ApplicationData.Current.LocalFolder;
var picPath = "\\Pictures\\newPic.jpg";
StorageFile captureFile = await folder.CreateFileAsync(picPath, CreationCollisionOption.GenerateUniqueName);
ImageEncodingProperties imageProperties = ImageEncodingProperties.CreateJpeg();
//Capture your picture into the given storage file
await newCapture.CapturePhotoToStorageFileAsync(imageProperties, captureFile);
That should solve your problem.
Related
My issue is quite simple.
I want to turn the flash On (and keep it On) on a Windows 10 universal app project but nothing I try works.
This is the code
MediaCapture MyMediaCapture = new MediaCapture();
var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
DeviceInformation cameraDevice =
allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null &&
x.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back);
cameraDevice = cameraDevice ?? allVideoDevices.FirstOrDefault();
if (cameraDevice == null)
{
Debug.WriteLine("No camera device found!");
}
else
{
await MyMediaCapture.InitializeAsync(new MediaCaptureInitializationSettings
{
VideoDeviceId = cameraDevice.Id
});
var MyVideoDeviceController = MyMediaCapture.VideoDeviceController;
var MyTorch = MyVideoDeviceController.TorchControl;
if (MyTorch.Supported)
{
var captureElement = new CaptureElement();
captureElement.Source = MyMediaCapture;
await MyMediaCapture.StartPreviewAsync();
FileStream tmp = new FileStream(System.IO.Path.GetTempFileName() + Guid.NewGuid().ToString() + ".mp4", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 10000, FileOptions.RandomAccess | FileOptions.DeleteOnClose);
var videoFile = await KnownFolders.VideosLibrary.CreateFileAsync(tmp.Name, CreationCollisionOption.GenerateUniqueName);
var encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Wvga);
await MyMediaCapture.StartRecordToStorageFileAsync(encodingProfile, videoFile);
MyTorch.PowerPercent = 100;
MyTorch.Enabled = true;
}
}
Edit: add code
It looks like you're trying to use an old method of accessing the flashlight which we no longer have to use in Windows 10 UWP development. Take a look at the new Lamp feature in Windows.Devices.Lights in this sample on GitHub.
It's a great starting point for using the flash independent of access the camera APIs.
You're on the right path. Depending on the device (because of driver-specific implementations), you'll have to start the preview or maybe even start a video recording session for the light to turn on.
Because of that, and to guarantee compatibility with most devices, I'd recommend you actually do both.
I am developing a voice recorder app for Windows Phone 8.1 that stores the recordings on the local storage and a cloud storage service.
Everything's almost done except the fact that being able to pause an ongoing recording is a strong requirement for this app and I have to get it done.
Now, since PauseRecordAsync() and ResumeRecordAsync() are not available for Windows Phone 8.1 in the MediaCapture class but they will be available in Windows 10, I had to make a workaround: Every time the pause button is pressed, an audio chunk is saved in the temp folder and that file is stored in an array. When the stop button is pressed, the last chunk is stored in the array and the following Concatenation function is called and a final audio temp file is created:
public async Task<IStorageFile> ConcatenateAudio([ReadOnlyArray]IStorageFile[] audioFiles, IStorageFolder outputFolder, string outputfileName)
{
IStorageFile _OutputFile = await outputFolder.CreateFileAsync(outputfileName, CreationCollisionOption.ReplaceExisting);
MediaComposition _MediaComposition = new MediaComposition();
MediaEncodingProfile _MediaEncodingProfile = MediaEncodingProfile.CreateM4a(AudioEncodingQuality.High);
foreach (IStorageFile _AudioFile in audioFiles)
{
if(_AudioFile != null)
{
BackgroundAudioTrack _BackgroundAudioTrack = await BackgroundAudioTrack.CreateFromFileAsync(_AudioFile);
MediaClip _MediaClip = MediaClip.CreateFromColor(Windows.UI.Colors.Black, _BackgroundAudioTrack.TrimmedDuration); // A dummy black video is created witn the size of the current audio chunk.
// Without this, the duration of the MediaComposition object is always 0.
// It's a messy workaround but it gets the job done.
// Windows 10 will dirrectly support PauseRecordAsync() and ResumeRecordAsync() for MediaCapture tho'. Yay! :D
_MediaClip.Volume = 0;
_BackgroundAudioTrack.Volume = 1;
_MediaComposition.Clips.Add(_MediaClip);
_MediaComposition.BackgroundAudioTracks.Add(_BackgroundAudioTrack);
}
}
TranscodeFailureReason _TranscodeFailureReason = await _MediaComposition.RenderToFileAsync(_OutputFile, MediaTrimmingPreference.Fast, _MediaEncodingProfile);
if (_TranscodeFailureReason != TranscodeFailureReason.None)
{
throw new Exception("Audio Concatenation Failed: " + _TranscodeFailureReason.ToString());
}
return _OutputFile;
}
The problem is that when I play the file, all the audio chunks are played from the beginning of the final audio file at the same time instead of playing the second one right after the first one ended and so on. They are all playing one over the other. The length of the file on the other hand is correct and after all audio files finished playing, it's total silence.
I figured it out. I had to manually set the delay for BackgroundAudioTrack.
Here is the working code:
public async Task<IStorageFile> ConcatenateAudio([ReadOnlyArray]IStorageFile[] audioFiles, IStorageFolder outputFolder, string outputfileName)
{
IStorageFile _OutputFile = await outputFolder.CreateFileAsync(outputfileName, CreationCollisionOption.ReplaceExisting);
MediaComposition _MediaComposition = new MediaComposition();
MediaEncodingProfile _MediaEncodingProfile = MediaEncodingProfile.CreateM4a(AudioEncodingQuality.High);
TimeSpan totalDelay = TimeSpan.Zero;
foreach (IStorageFile _AudioFile in audioFiles)
{
if (_AudioFile != null)
{
BackgroundAudioTrack _BackgroundAudioTrack = await BackgroundAudioTrack.CreateFromFileAsync(_AudioFile);
MediaClip _MediaClip = MediaClip.CreateFromColor(Windows.UI.Colors.Black, _BackgroundAudioTrack.TrimmedDuration); // A dummy black video is created witn the size of the current audio chunk.
// Without this, the duration of the MediaComposition object is always 0.
// It's a messy workaround but it gets the job done.
// Windows 10 will dirrectly support PauseRecordAsync() and ResumeRecordAsync() for MediaCapture tho'. Yay! :D
_MediaClip.Volume = 0;
_BackgroundAudioTrack.Volume = 1;
_MediaComposition.Clips.Add(_MediaClip);
_MediaComposition.BackgroundAudioTracks.Add(_BackgroundAudioTrack);
_BackgroundAudioTrack.Delay = totalDelay;
totalDelay += _BackgroundAudioTrack.TrimmedDuration;
}
}
TranscodeFailureReason _TranscodeFailureReason = await _MediaComposition.RenderToFileAsync(_OutputFile, MediaTrimmingPreference.Fast, _MediaEncodingProfile);
if (_TranscodeFailureReason != TranscodeFailureReason.None)
{
throw new Exception("Audio Concatenation Failed: " + _TranscodeFailureReason.ToString());
}
return _OutputFile;
}
I have developed windows 8.1 store app, it need to be capture photo by using back camera and post.
MediaCaptureInitializationSettings _captureSettings = new var devices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
foreach (var device in devices)
{
if (device.EnclosureLocation != null && device.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back)
{
deviceId = device.Id;
break;
}
}
if (!string.IsNullOrEmpty(deviceId))
{
_captureSettings.AudioDeviceId = "";
_captureSettings.VideoDeviceId = deviceId;
_captureSettings.PhotoCaptureSource = Windows.Media.Capture.PhotoCaptureSource.Photo;
_captureSettings.StreamingCaptureMode = Windows.Media.Capture.StreamingCaptureMode.Video;
}
captureManager = new MediaCapture();
await captureManager.InitializeAsync(_captureSettings);
await captureManager.ClearEffectsAsync(MediaStreamType.Photo);
capturePreview1.Source = captureManager;
await captureManager.StartPreviewAsync();
</code>
Here i am getting two devices but that devices EnclosureLocation is null, so i can't find which one is front and back camera.
so have decided to get second device from list
<code>
deviceId = devices[1].Id;
</code>
but it throws an error like "The current capture source does not have an independent photo stream."
in the line of initializing MediaCapture
<code>
await captureManager.InitializeAsync(_captureSettings);
</code>
i have tried in windows surface pro 2 and acer devices.
Please advise. Thanks in advance.
Try to organise your code better, you got two equals signs on the same line and your code is not well formated so it's hard to read.
To use Camera in Windows 8.1 stop app I use this code :
// First need to find all webcams
DeviceInformationCollection webcamList = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture)
// Then I do a query to find the front webcam
DeviceInformation frontWebcam = (from webcam in webcamList
where webcam.EnclosureLocation != null
&& webcam.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Front
select webcam).FirstOrDefault();
// Same for the back webcam
DeviceInformation backWebcam = (from webcam in webcamList
where webcam.EnclosureLocation != null
&& webcam.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back
select webcam).FirstOrDefault();
// Then you need to initialize your MediaCapture
var captureManager = new MediaCapture();
await captureManager.InitializeAsync(new MediaCaptureInitializationSettings
{
// Choose the webcam you want (backWebcam or frontWebcam)
VideoDeviceId = backWebcam.Id,
AudioDeviceId = "",
StreamingCaptureMode = StreamingCaptureMode.Video,
PhotoCaptureSource = PhotoCaptureSource.VideoPreview
});
// Set the source of the CaptureElement to your MediaCapture
capturePreview1.Source = captureManager;
// Start the preview
await captureManager.StartPreviewAsync();
This way it's easier to read. The code is not very different, MediaCaptureInitializationSettings is not the same.
This code works for me on Surface 2 RT and Nokia 635 so it should work for you.
Edit:
Seems it works on devices with Windows RT but on full windows 8.1 devices it's always null.
Msdn says that:
If no enclosure location information is available, the property will
be null
so what you can do is first try to see if you find a backwebcam and if it's null take the last one;
DeviceInformation backWebcam = (from webcam in webcamList
where webcam.EnclosureLocation != null
&& webcam.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back
select webcam).FirstOrDefault();
if (backWebcam == null)
{
backWebcam = webcamList.Last();
}
But you are not sure the last one in the collection is the back one, so you should add a button to let the user switch camera
If you change camera,
await captureManager.StopPreviewAsync();
await captureManager.InitializeAsync(new MediaCaptureInitializationSettings
{
// Choose an other webcam
VideoDeviceId = //id of the new webcam,
AudioDeviceId = "",
StreamingCaptureMode = StreamingCaptureMode.Video,
PhotoCaptureSource = PhotoCaptureSource.VideoPreview
});
await captureManager.StartPreviewAsync();
this way you can be sure the user can choose the right camera even is you programmaticaly cannot tell which one is which
So I have taken some Photos on my windows phone emulator and I am then trying to find them in my application.
So Far I have:
PictureCollection CameraRollPictures;
using (var library = new MediaLibrary())
{
//taking all albums
PictureAlbumCollection allAlbums = library.RootPictureAlbum.Albums;
//taking Camera Roll album separately from all album
PictureAlbum cameraRoll = allAlbums.Where(album => album.Name == "Camera Roll").FirstOrDefault();
// here you will get camera roll picture list
CameraRollPictures = cameraRoll.Pictures;
}
But this keeps crashing because cameraRoll = null. Is this feature available on WP8 emulator or am I doing something wrong?
My method to get photos is from this stackoverflow question
EDIT
I have also tried album.Name == "Camera Roll"
So the answer was simple... My method worked perfectly but I needed to:
go into the WMAppManifest.Xml
go to Capabilities
tick ID_CAP_MEDIALIB_PHOTO
This provides read-only access to photos in the media library
MediaSource mediaSource = MediaSource.GetAvailableMediaSources()
.First((source => source.MediaSourceType == MediaSourceType.LocalDevice));
using (MediaLibrary mediaLibrary = new MediaLibrary(mediaSource))
{
PictureAlbum cameraRollAlbum = mediaLibrary.RootPictureAlbum.Albums.First((album) => album.Name == "Camera Roll");
}
or use PhotoChooserTask
You can upload Images to an Emulator as mentioned here
Can anyone say how to toggle flashlight in Windows Phone 8.1 using C#? It seems like there are lots of API changes in Windows Phone 8.1 and most of the API's in WP 8.0 are not supported. Answers are highly appreciated.
I'm able to use TorchControl on my Lumia 820 like this - first you have to specify which camera you will use - the default is front (I think that's why you may find some problems) and we want the back one - the one with flash light. Sample code:
// edit - I forgot to show GetCameraID:
private static async Task<DeviceInformation> GetCameraID(Windows.Devices.Enumeration.Panel desiredCamera)
{
DeviceInformation deviceID = (await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture))
.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredCamera);
if (deviceID != null) return deviceID;
else throw new Exception(string.Format("Camera of type {0} doesn't exist.", desiredCamera));
}
// init camera
async private void InitCameraBtn_Click(object sender, RoutedEventArgs e)
{
var cameraID = await GetCameraID(Windows.Devices.Enumeration.Panel.Back);
captureManager = new MediaCapture();
await captureManager.InitializeAsync(new MediaCaptureInitializationSettings
{
StreamingCaptureMode = StreamingCaptureMode.Video,
PhotoCaptureSource = PhotoCaptureSource.VideoPreview,
AudioDeviceId = string.Empty,
VideoDeviceId = cameraID.Id
});
}
// then to turn on/off camera
var torch = captureManager.VideoDeviceController.TorchControl;
if (torch.Supported) torch.Enabled = true;
// turn off
if (torch.Supported) torch.Enabled = false;
Note that it's a good idea to call captureManager.Dispose() after you finish with it.
Note also that on some phones to turn on torch/flashlight you will need to start preview first.
Windows Phone 8.1 is the first version with a dedicated API for controlling the camera light. This API stems from Windows 8.1 but is usable in Windows Phone 8.1 projects and in Windows Phone Silverlight 8.1 projects.
var mediaDev = new MediaCapture();
await mediaDev.InitializeAsync();
var videoDev = mediaDev.VideoDeviceController;
var tc = videoDev.TorchControl;
if (tc.Supported)
{
if (tc.PowerSupported)
tc.PowerPercent = 100;
tc.Enabled = true;
}
Note:
Note: TorchControl.Supported returns false on most phones in WP8.1 developer preview. It is expected to be fixed by a firmware update by the time WP 8.1 is released. Tested Phones at the time of writing: Lumia 620, 822, 1020: not working, Lumia 1520: working.
In Nokia Lumia 1520, you use FlashControl to toggle the flash light instead of TorchControl.
//to switch OFF flash light
mediacapture.VideoDeviceController.FlashControl.Enabled = false;
//to switch ON flash light
mediacapture.VideoDeviceController.FlashControl.Enabled = true;
Doesn't work on my Lumia 1520. You need to start video recording to get flashlight working:
var videoEncodingProperties = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Vga);
var videoStorageFile = await KnownFolders.VideosLibrary.CreateFileAsync("tempVideo.mp4", CreationCollisionOption.GenerateUniqueName);
await captureManager.StartRecordToStorageFileAsync(videoEncodingProperties, videoStorageFile);
In my Lumia 1520. I need to start video recording and start preview to get flashlight working:
await captureManager.StartPreviewAsync();