diff --git a/src/SamplesApp/UITests.Shared/Windows_Media/CameraCaptureUISample.xaml b/src/SamplesApp/UITests.Shared/Windows_Media/CameraCaptureUISample.xaml
index 26dcc44e00c1..83ffbe072cc6 100644
--- a/src/SamplesApp/UITests.Shared/Windows_Media/CameraCaptureUISample.xaml
+++ b/src/SamplesApp/UITests.Shared/Windows_Media/CameraCaptureUISample.xaml
@@ -16,5 +16,7 @@
+
diff --git a/src/SamplesApp/UITests.Shared/Windows_Media/CameraCaptureUISample.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_Media/CameraCaptureUISample.xaml.cs
index c8036447b7b9..8cf42b25fdaa 100644
--- a/src/SamplesApp/UITests.Shared/Windows_Media/CameraCaptureUISample.xaml.cs
+++ b/src/SamplesApp/UITests.Shared/Windows_Media/CameraCaptureUISample.xaml.cs
@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
+using System.IO;
using Uno.UI.Samples.Controls;
using Windows.Media.Capture;
using Windows.UI.Xaml;
@@ -47,7 +48,16 @@ private async void CaptureVideo_Click(object sender, RoutedEventArgs e)
{
var captureUI = new CameraCaptureUI();
- _ = await captureUI.CaptureFileAsync(CameraCaptureUIMode.Video);
+ var result = await captureUI.CaptureFileAsync(CameraCaptureUIMode.Video);
+
+ if (result != null)
+ {
+ videoSize.Text = $"Captured file: {result.Path}, Size: {new FileInfo(result?.Path!).Length}";
+ }
+ else
+ {
+ videoSize.Text = "Nothing was selected";
+ }
}
#endif
}
diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.Media.Capture/CameraCaptureUIVideoCaptureSettings.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.Media.Capture/CameraCaptureUIVideoCaptureSettings.cs
index 62f68de31ede..2669e8bda3ed 100644
--- a/src/Uno.UWP/Generated/3.0.0.0/Windows.Media.Capture/CameraCaptureUIVideoCaptureSettings.cs
+++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.Media.Capture/CameraCaptureUIVideoCaptureSettings.cs
@@ -36,7 +36,7 @@ public float MaxDurationInSeconds
}
}
#endif
-#if false || false || false || false || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__
+#if false
[global::Uno.NotImplemented("__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")]
public global::Windows.Media.Capture.CameraCaptureUIVideoFormat Format
{
diff --git a/src/Uno.UWP/Media/Capture/CameraCaptureUI.cs b/src/Uno.UWP/Media/Capture/CameraCaptureUI.cs
index b2f8e51a93a8..c58ce1329df3 100644
--- a/src/Uno.UWP/Media/Capture/CameraCaptureUI.cs
+++ b/src/Uno.UWP/Media/Capture/CameraCaptureUI.cs
@@ -21,6 +21,7 @@ public partial class CameraCaptureUI
public CameraCaptureUI()
{
+ VideoSettings.Format = CameraCaptureUIVideoFormat.Mp4;
}
public global::Windows.Foundation.IAsyncOperation CaptureFileAsync(global::Windows.Media.Capture.CameraCaptureUIMode mode)
diff --git a/src/Uno.UWP/Media/Capture/CameraCaptureUI.iOS.cs b/src/Uno.UWP/Media/Capture/CameraCaptureUI.iOS.cs
index ee2a38ba7430..4c9357dac1ea 100644
--- a/src/Uno.UWP/Media/Capture/CameraCaptureUI.iOS.cs
+++ b/src/Uno.UWP/Media/Capture/CameraCaptureUI.iOS.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AVFoundation;
@@ -44,6 +45,11 @@ private async Task CaptureFile(CancellationToken ct, CameraCaptureU
#pragma warning restore CA1416
picker.CameraCaptureMode = UIImagePickerControllerCameraCaptureMode.Video;
+ if (VideoSettings.Format != CameraCaptureUIVideoFormat.Mp4)
+ {
+ throw new NotSupportedException("The capture format CameraCaptureUIVideoFormat.Mp4 is the only supported format");
+ }
+
await ValidateCameraAccess();
await ValidateMicrophoneAccess();
break;
@@ -75,36 +81,139 @@ private async Task CaptureFile(CancellationToken ct, CameraCaptureU
if (result != null)
{
- var image = result.ValueForKey(new NSString("UIImagePickerControllerOriginalImage")) as UIImage;
- var metadata = result.ValueForKey(new NSString("UIImagePickerControllerOriginalImage")) as UIImage;
-
- var correctedImage = FixOrientation(image);
+ if (result.ValueForKey(new NSString("UIImagePickerControllerOriginalImage")) is UIImage image)
+ {
+ var correctedImage = FixOrientation(image);
- (Stream data, string extension) GetImageStream()
+ (Stream data, string extension) GetImageStream()
+ {
+ return PhotoSettings.Format switch
+ {
+ CameraCaptureUIPhotoFormat.Jpeg => (image.AsJPEG().AsStream(), ".jpg"),
+ CameraCaptureUIPhotoFormat.Png => (image.AsPNG().AsStream(), ".png"),
+ _ => throw new NotSupportedException($"{PhotoSettings.Format} is not supported"),
+ };
+ };
+
+ var (data, extension) = GetImageStream();
+ return await CreateTempImage(data, extension);
+ }
+ else
{
- switch (PhotoSettings.Format)
+ var assetUrl = result[UIImagePickerController.MediaURL] as NSUrl;
+ PHAsset phAsset = null;
+
+ if (this.Log().IsEnabled(LogLevel.Debug))
{
- case CameraCaptureUIPhotoFormat.Jpeg:
- return (image.AsJPEG().AsStream(), ".jpg");
+ this.Log().Debug($"Asset url {assetUrl}");
+ }
- case CameraCaptureUIPhotoFormat.Png:
- return (image.AsPNG().AsStream(), ".png");
+ if (assetUrl is not null)
+ {
+ if (OperatingSystem.IsIOSVersionAtLeast(11, 0))
+ {
+ if (!assetUrl.Scheme.Equals("assets-library", StringComparison.OrdinalIgnoreCase))
+ {
+ var doc = new UIDocument(assetUrl);
+ var fullPath = doc.FileUrl?.Path;
+
+ if (fullPath is null)
+ {
+ if (this.Log().IsEnabled(LogLevel.Warning))
+ {
+ this.Log().LogWarning($"Unable determine file path from asset library");
+ }
+
+ return null;
+ }
+ else
+ {
+ return await ConvertToMp4(fullPath);
+ }
+ }
+
+ phAsset = result.ValueForKey(UIImagePickerController.PHAsset) as PHAsset;
+ }
+ }
- default:
- throw new NotSupportedException($"{PhotoSettings.Format} is not supported");
+ if (phAsset == null)
+ {
+#if !__MACCATALYST__
+ assetUrl = result[UIImagePickerController.ReferenceUrl] as NSUrl;
+
+ if (this.Log().IsEnabled(LogLevel.Debug))
+ {
+ this.Log().Debug($"Asset url {assetUrl}");
+ }
+
+ if (assetUrl != null)
+ {
+ phAsset = PHAsset.FetchAssets(new NSUrl[] { assetUrl }, null)?.LastObject as PHAsset;
+ }
+#endif
}
- };
- var (data, extension) = GetImageStream();
- return await CreateTempImage(data, extension);
- }
- else
- {
- return null;
+ if (phAsset is not null)
+ {
+ var originalFilename = PHAssetResource.GetAssetResources(phAsset).FirstOrDefault()?.OriginalFilename;
+
+ if (originalFilename is null)
+ {
+ if (this.Log().IsEnabled(LogLevel.Warning))
+ {
+ this.Log().LogWarning($"Unable determine Asset Resources from PHAssetResource");
+ }
+ }
+ else
+ {
+ return await ConvertToMp4(originalFilename);
+ }
+ }
+ else
+ {
+ if (this.Log().IsEnabled(LogLevel.Warning))
+ {
+ this.Log().LogWarning($"Could not determine asset url");
+ }
+ }
+ }
}
+
+ return null;
}
}
+ private async Task ConvertToMp4(string originalFilename)
+ {
+ if (originalFilename == null)
+ {
+ return null;
+ }
+
+ var outputFilePath = Path.Combine(ApplicationData.Current.TemporaryFolder.Path, Guid.NewGuid() + ".mp4");
+
+ if (this.Log().IsEnabled(LogLevel.Debug))
+ {
+ this.Log().Debug($"Converting {originalFilename} to {outputFilePath}");
+ }
+
+ var asset = AVAsset.FromUrl(NSUrl.FromFilename(originalFilename));
+
+ AVAssetExportSession export = new(asset, AVAssetExportSession.PresetPassthrough);
+
+ export.OutputUrl = NSUrl.FromFilename(outputFilePath);
+ export.OutputFileType = AVFileTypesExtensions.GetConstant(AVFileTypes.Mpeg4);
+ export.ShouldOptimizeForNetworkUse = true;
+
+ await export.ExportTaskAsync();
+
+ if (this.Log().IsEnabled(LogLevel.Debug))
+ {
+ this.Log().Debug($"Done converting to {outputFilePath}");
+ }
+
+ return await StorageFile.GetFileFromPathAsync(outputFilePath);
+ }
// As of iOS 10, usage description keys are required for many more permissions
private static bool IsUsageKeyDefined(string usageKey)
diff --git a/src/Uno.UWP/Media/Capture/CameraCaptureUIVideoCaptureSettings.cs b/src/Uno.UWP/Media/Capture/CameraCaptureUIVideoCaptureSettings.cs
index 4b43717b93be..3e51c647b8f8 100644
--- a/src/Uno.UWP/Media/Capture/CameraCaptureUIVideoCaptureSettings.cs
+++ b/src/Uno.UWP/Media/Capture/CameraCaptureUIVideoCaptureSettings.cs
@@ -32,20 +32,12 @@ public float MaxDurationInSeconds
}
}
#endif
-#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__
- [global::Uno.NotImplemented]
- public global::Windows.Media.Capture.CameraCaptureUIVideoFormat Format
+
+ public CameraCaptureUIVideoFormat Format
{
- get
- {
- throw new global::System.NotImplementedException("The member CameraCaptureUIVideoFormat CameraCaptureUIVideoCaptureSettings.Format is not implemented in Uno.");
- }
- set
- {
- global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.Media.Capture.CameraCaptureUIVideoCaptureSettings", "CameraCaptureUIVideoFormat CameraCaptureUIVideoCaptureSettings.Format");
- }
+ get; set;
}
-#endif
+
#if __ANDROID__ || __IOS__ || IS_UNIT_TESTS || __WASM__
[global::Uno.NotImplemented]
public bool AllowTrimming