public static async Task <string> GetIOSFilePath(this PHAsset photo) { var tcs = new TaskCompletionSource <NSUrl>(); if (photo.MediaType == PHAssetMediaType.Image) { var options = new PHContentEditingInputRequestOptions(); options.CanHandleAdjustmentData = _ => true; photo.RequestContentEditingInput(options, (contentEditingInput, requestStatusInfo) => { tcs.SetResult(contentEditingInput.FullSizeImageUrl); }); } else if (photo.MediaType == PHAssetMediaType.Video) { var options = new PHVideoRequestOptions(); options.Version = PHVideoRequestOptionsVersion.Original; PHImageManager.DefaultManager.RequestAvAsset(photo, options, (asset, audioMix, info) => { if (asset is AVUrlAsset urlAsset) { tcs.SetResult(urlAsset.Url); return; } tcs.SetException(new InvalidDataException("RequestAvAsset didn't get AVUrlAsset")); }); } var origfilepath = await tcs.Task.ConfigureAwait(false); return(origfilepath.Path); }
private static string StorePickedVideo(PHAsset asset) { var tcs = new TaskCompletionSource <string>(); var task = tcs.Task; var imageManager = PHImageManager.DefaultManager; using (var requestOptions = new PHVideoRequestOptions { NetworkAccessAllowed = true, DeliveryMode = PHVideoRequestOptionsDeliveryMode.MediumQualityFormat }) { imageManager.RequestExportSession(asset, requestOptions, AVAssetExportSession.PresetPassthrough, (exportSession, info) => { Task.Factory.StartNew(async() => { var targetDir = Environment.GetFolderPath(Environment.SpecialFolder.Personal); var error = (NSError)info["PHImageErrorKey"]; if (error != null) { var description = error.LocalizedDescription; var reason = error.UserInfo.ValueForKey((NSString)"NSUnderlyingError"); tcs.SetException(new FileLoadException($"{description}. {reason}")); return; } var resources = PHAssetResource.GetAssetResources(asset); var orgFilename = resources[0].OriginalFilename; var path = Path.Combine(targetDir, orgFilename); File.Delete(path); exportSession.OutputUrl = new NSUrl($"file://{path}"); exportSession.OutputFileType = AVFileType.Mpeg4; await exportSession.ExportTaskAsync(); if (exportSession.Status == AVAssetExportSessionStatus.Completed) { tcs.TrySetResult(path); } else { tcs.SetException(new Exception(exportSession.Error.Description)); } }); }); } return(task.Result); }
private void HandleImage(IEnumerable <PHObject> images) { foreach (PHAsset image in images) { if (image.MediaType == PHAssetMediaType.Image) { PHImageRequestOptions options = new PHImageRequestOptions() { NetworkAccessAllowed = false, ResizeMode = PHImageRequestOptionsResizeMode.Exact, Version = PHImageRequestOptionsVersion.Original }; PHImageManager.DefaultManager.RequestImageData(image, options, async(d, t, o, i) => { string path = ((NSUrl)i["PHImageFileURLKey"])?.Path; string mimeType = UTType.GetPreferredTag(t, UTType.TagClassMIMEType); await _probe.CreateAndStoreDatumAsync(path, mimeType, (DateTime)image.CreationDate); }); } else if (image.MediaType == PHAssetMediaType.Video) { PHVideoRequestOptions options = new PHVideoRequestOptions() { NetworkAccessAllowed = false, Version = PHVideoRequestOptionsVersion.Original }; PHImageManager.DefaultManager.RequestAvAsset(image, options, async(a, _, i) => { if (a is AVUrlAsset urlAsset) { string path = urlAsset.Url.Path; string extension = urlAsset.Url.PathExtension; string uniformTypeIdentifier = UTType.CreatePreferredIdentifier(UTType.TagClassFilenameExtension, extension, null); string mimeType = UTType.GetPreferredTag(uniformTypeIdentifier, UTType.TagClassMIMEType); await _probe.CreateAndStoreDatumAsync(path, mimeType, (DateTime)image.CreationDate); } }); } } }
private void ChangeVideo(PHAsset asset, PHImageManager imageManager, PHVideoRequestOptions options) { DispatchQueue.DefaultGlobalQueue.DispatchAsync(() => imageManager?.RequestAvAsset(asset, options, (ass, mix, info) => DispatchQueue.MainQueue.DispatchAsync(() => { CurrentMediaType = MediaType.Video; _albumView.ImageCropView.Hidden = true; _albumView.MovieView.Hidden = false; var urlAsset = ass as AVUrlAsset; if (urlAsset == null) { return; } _albumView.MoviePlayerController.ContentUrl = urlAsset.Url; _albumView.MoviePlayerController.PrepareToPlay(); }))); }
async void FinishedPickingAssets(object sender, MultiAssetEventArgs args) { IList <MediaFile> results = new List <MediaFile>(); TaskCompletionSource <IList <MediaFile> > tcs = new TaskCompletionSource <IList <MediaFile> >(); var options = new Photos.PHImageRequestOptions() { NetworkAccessAllowed = true }; options.Synchronous = false; options.ResizeMode = PHImageRequestOptionsResizeMode.Fast; options.DeliveryMode = PHImageRequestOptionsDeliveryMode.HighQualityFormat; bool completed = false; for (var i = 0; i < args.Assets.Length; i++) { var asset = args.Assets[i]; string fileName = string.Empty; if (UIDevice.CurrentDevice.CheckSystemVersion(9, 0)) { fileName = PHAssetResource.GetAssetResources(asset).FirstOrDefault().OriginalFilename; } switch (asset.MediaType) { case PHAssetMediaType.Video: PHImageManager.DefaultManager.RequestImageForAsset(asset, new SizeF(150.0f, 150.0f), PHImageContentMode.AspectFill, options, async(img, info) => { var startIndex = fileName.IndexOf(".", StringComparison.CurrentCulture); string path = ""; if (startIndex != -1) { path = FileHelper.GetOutputPath(MediaFileType.Image, TemporalDirectoryName, $"{fileName.Substring(0, startIndex)}-THUMBNAIL.JPG"); } else { path = FileHelper.GetOutputPath(MediaFileType.Image, TemporalDirectoryName, string.Empty); } if (!File.Exists(path)) { img.AsJPEG().Save(path, true); } TaskCompletionSource <string> tvcs = new TaskCompletionSource <string>(); var vOptions = new PHVideoRequestOptions(); vOptions.NetworkAccessAllowed = true; vOptions.Version = PHVideoRequestOptionsVersion.Original; vOptions.DeliveryMode = PHVideoRequestOptionsDeliveryMode.FastFormat; PHImageManager.DefaultManager.RequestAvAsset(asset, vOptions, (avAsset, audioMix, vInfo) => { var vPath = FileHelper.GetOutputPath(MediaFileType.Video, TemporalDirectoryName, fileName); if (!File.Exists(vPath)) { AVAssetExportSession exportSession = new AVAssetExportSession(avAsset, AVAssetExportSession.PresetHighestQuality); exportSession.OutputUrl = NSUrl.FromFilename(vPath); exportSession.OutputFileType = AVFileType.QuickTimeMovie; exportSession.ExportAsynchronously(() => { Console.WriteLine(exportSession.Status); tvcs.TrySetResult(vPath); //exportSession.Dispose(); }); } }); var videoUrl = await tvcs.Task; var meFile = new MediaFile() { Type = MediaFileType.Video, Path = videoUrl, PreviewPath = path }; results.Add(meFile); OnMediaPicked?.Invoke(this, meFile); if (args.Assets.Length == results.Count && !completed) { completed = true; tcs.TrySetResult(results); } }); break; default: Photos.PHImageManager.DefaultManager.RequestImageData(asset, options, (data, dataUti, orientation, info) => { string path = FileHelper.GetOutputPath(MediaFileType.Image, TemporalDirectoryName, fileName); if (!File.Exists(path)) { Debug.WriteLine(dataUti); var imageData = data; //var image = UIImage.LoadFromData(imageData); //if (imageScale < 1.0f) //{ // //begin resizing image // image = image.ResizeImageWithAspectRatio((float)imageScale); //} //if (imageQuality < 100) //{ // imageData = image.AsJPEG(Math.Min(imageQuality,100)); //} imageData?.Save(path, true); } var meFile = new MediaFile() { Type = MediaFileType.Image, Path = path, PreviewPath = path }; results.Add(meFile); OnMediaPicked?.Invoke(this, meFile); if (args.Assets.Length == results.Count && !completed) { completed = true; tcs.TrySetResult(results); } }); break; } } mediaPickTcs?.TrySetResult(await tcs.Task); }
async void FinishedPickingAssets(object sender, MultiAssetEventArgs args) { var picker = (GMImagePickerController)sender; picker.FinishedPickingAssets -= FinishedPickingAssets; picker.Canceled -= OnPickerCanceled; // synchronous: NO.异步。 // a.deliveryMode: Opportunistic: 会返回多张图片 // 1). ResizeMode.None: 先返回低清的缩略图,再返回原图大小 // 2). ResizeMode.Fast: 先返回低清的缩略图,再返回的原图会使用targetSize来最优解码图片,获得的图片大小可能比targetSize大 // 3). ResizeMode.Exact: 先返回低清的缩略图,再返回的原图会使用targetSize的高质量图 // b.deliveryMode: HighQualityFormat: 只会返回一张高清图片 // 1). ResizeMode.None: 返回的是原图大小 // 2). ResizeMode.Fast: 当原图是压缩图时,会使用targetSize来最优解码图片,获得的图片大小可能比targetSize大 // 3). ResizeMode.Exact: 解压和Fast一样,但是返回的是指定targetSize的高质量图 // c.deliveryMode: FastFormat: 只会返回一张图片,并且可能是低清图 // 1). ResizeMode.None: 返回一张低清图 // 2). ResizeMode.Fast: 返回一张低清图 // 3). ResizeMode.Exact: 返回一张低清图 var options = new PHImageRequestOptions { NetworkAccessAllowed = true, Synchronous = false, DeliveryMode = PHImageRequestOptionsDeliveryMode.HighQualityFormat, ResizeMode = PHImageRequestOptionsResizeMode.Exact, }; var tcs = new TaskCompletionSource <object>(); bool completed = false; List <FileData> result = new List <FileData>(); for (var i = 0; i < args.Assets.Length; i++) { var asset = args.Assets[i]; switch (asset.MediaType) { case PHAssetMediaType.Video: // 未测 PHImageManager.DefaultManager.RequestImageForAsset( asset, new SizeF(FileData.ThumbSize, FileData.ThumbSize), PHImageContentMode.AspectFit, options, async(img, info) => { // 获取路径,麻烦 TaskCompletionSource <NSUrl> tcsUrl = new TaskCompletionSource <NSUrl>(); var vOptions = new PHVideoRequestOptions { NetworkAccessAllowed = true, Version = PHVideoRequestOptionsVersion.Original, DeliveryMode = PHVideoRequestOptionsDeliveryMode.FastFormat, }; PHImageManager.DefaultManager.RequestAvAsset( asset, vOptions, (avAsset, audioMix, vInfo) => { if (avAsset is AVUrlAsset avUrl) { tcsUrl.TrySetResult(avUrl.Url); } else { tcsUrl.TrySetResult(null); } }); NSUrl url = await tcsUrl.Task; // 生成文件描述和缩略图 var fd = ParseUrl(url); fd.Desc = $"{asset.PixelWidth} x {asset.PixelHeight} ({fd.Ext.TrimStart('.')})"; fd.ThumbPath = Path.Combine(Kit.CachePath, Kit.NewGuid + "-t.jpg"); img.AsJPEG().Save(fd.ThumbPath, true); result.Add(fd); if (args.Assets.Length == result.Count && !completed) { completed = true; tcs.TrySetResult(null); } }); break; default: PHImageManager.DefaultManager.RequestImageForAsset( asset, new SizeF(FileData.ThumbSize, FileData.ThumbSize), PHImageContentMode.AspectFit, options, async(img, info) => { // 获取路径,麻烦 TaskCompletionSource <NSUrl> tcsUrl = new TaskCompletionSource <NSUrl>(); asset.RequestContentEditingInput(new PHContentEditingInputRequestOptions(), (input, _) => { tcsUrl.TrySetResult(input.FullSizeImageUrl); }); NSUrl url = await tcsUrl.Task; // 生成文件描述和缩略图 var fd = ParseUrl(url); fd.Desc = $"{asset.PixelWidth} x {asset.PixelHeight} ({fd.Ext.TrimStart('.')})"; if (asset.PixelWidth > FileData.ThumbSize || asset.PixelHeight > FileData.ThumbSize) { fd.ThumbPath = Path.Combine(Kit.CachePath, Kit.NewGuid + "-t.jpg"); img.AsJPEG().Save(fd.ThumbPath, true); } result.Add(fd); if (args.Assets.Length == result.Count && !completed) { completed = true; tcs.TrySetResult(null); } }); break; } } // 用临时tcs等待比直接在回调方法中用_tcs速度大幅提高!!! await tcs.Task; _tcs.TrySetResult(result); }
async Task <IList <MediaAsset> > LoadMediaAsync() { IList <MediaAsset> assets = new List <MediaAsset>(); var imageManager = new PHCachingImageManager(); var hasPermission = await RequestPermissionAsync(); if (hasPermission) { await Task.Run(async() => { var thumbnailRequestOptions = new PHImageRequestOptions(); thumbnailRequestOptions.ResizeMode = PHImageRequestOptionsResizeMode.Fast; thumbnailRequestOptions.DeliveryMode = PHImageRequestOptionsDeliveryMode.FastFormat; thumbnailRequestOptions.NetworkAccessAllowed = true; thumbnailRequestOptions.Synchronous = true; var requestOptions = new PHImageRequestOptions(); requestOptions.ResizeMode = PHImageRequestOptionsResizeMode.Exact; requestOptions.DeliveryMode = PHImageRequestOptionsDeliveryMode.HighQualityFormat; requestOptions.NetworkAccessAllowed = true; requestOptions.Synchronous = true; var fetchOptions = new PHFetchOptions(); fetchOptions.SortDescriptors = new NSSortDescriptor[] { new NSSortDescriptor("creationDate", false) }; fetchOptions.Predicate = NSPredicate.FromFormat($"mediaType == {(int)PHAssetMediaType.Image} || mediaType == {(int)PHAssetMediaType.Video}"); var fetchResults = PHAsset.FetchAssets(fetchOptions); var tmpPath = Path.GetTempPath(); var allAssets = fetchResults.Select(p => p as PHAsset).ToArray(); var thumbnailSize = new CGSize(300.0f, 300.0f); imageManager.StartCaching(allAssets, thumbnailSize, PHImageContentMode.AspectFit, thumbnailRequestOptions); imageManager.StartCaching(allAssets, PHImageManager.MaximumSize, PHImageContentMode.AspectFit, requestOptions); foreach (var result in fetchResults) { var phAsset = (result as PHAsset); var name = PHAssetResource.GetAssetResources(phAsset)?.FirstOrDefault()?.OriginalFilename; var asset = new MediaAsset() { Id = phAsset.LocalIdentifier, Name = name, Type = phAsset.MediaType == PHAssetMediaType.Image ? MediaAssetType.Image : MediaAssetType.Video, }; imageManager.RequestImageForAsset(phAsset, thumbnailSize, PHImageContentMode.AspectFit, thumbnailRequestOptions, (image, info) => { if (image != null) { NSData imageData = null; if (image.CGImage.RenderingIntent == CGColorRenderingIntent.Default) { imageData = image.AsJPEG(0.8f); } else { imageData = image.AsPNG(); } if (imageData != null) { var fileName = Path.Combine(tmpPath, $"tmp_thumbnail_{Path.GetFileNameWithoutExtension(name)}.jpg"); NSError error = null; imageData.Save(fileName, true, out error); if (error == null) { asset.PreviewPath = fileName; } } } }); switch (phAsset.MediaType) { case PHAssetMediaType.Image: imageManager.RequestImageForAsset(phAsset, PHImageManager.MaximumSize, PHImageContentMode.AspectFit, requestOptions, (image, info) => { if (image != null) { NSData imageData = null; if (image.CGImage.RenderingIntent == CGColorRenderingIntent.Default) { imageData = image.AsJPEG(0.8f); } else { imageData = image.AsPNG(); } if (imageData != null) { var fileName = Path.Combine(tmpPath, $"tmp_{name}"); NSError error = null; imageData.Save(fileName, true, out error); if (error == null) { asset.Path = fileName; } } } }); break; case PHAssetMediaType.Video: var videoRequestOptions = new PHVideoRequestOptions(); videoRequestOptions.NetworkAccessAllowed = true; var tcs = new TaskCompletionSource <bool>(); imageManager.RequestAvAsset(phAsset, null, (vAsset, audioMix, info) => { var avAsset = vAsset as AVUrlAsset; var avData = NSData.FromUrl(avAsset.Url); NSError error = null; var path = Path.Combine(tmpPath, $"tmp_{name}"); avData.Save(path, true, out error); if (error == null) { asset.Path = path; tcs.TrySetResult(true); } else { tcs.TrySetResult(false); } }); await tcs.Task; break; } UIApplication.SharedApplication.InvokeOnMainThread(delegate { OnMediaAssetLoaded?.Invoke(this, new MediaEventArgs(asset)); }); assets.Add(asset); if (requestStop) { break; } } }); imageManager.StopCaching(); } return(assets); }
partial void Play(NSObject sender) { // An AVPlayerLayer has already been created for this asset; just play it. if (playerLayer != null) { playerLayer.Player.Play(); } else { var options = new PHVideoRequestOptions { NetworkAccessAllowed = true, DeliveryMode = PHVideoRequestOptionsDeliveryMode.Automatic, ProgressHandler = (double progress, NSError error, out bool stop, NSDictionary info) => { stop = false; // Handler might not be called on the main queue, so re-dispatch for UI work. DispatchQueue.MainQueue.DispatchSync(() => { ProgressView.Progress = (float)progress; }); } }; // Request an AVAsset for the displayed PHAsset and set up a layer for playing it. PHImageManager.DefaultManager.RequestPlayerItem(Asset, options, (playerItem, info) => { DispatchQueue.MainQueue.DispatchSync(() => { if (this.playerLayer != null || playerItem == null) { return; } // Create an AVPlayer and AVPlayerLayer with the AVPlayerItem. AVPlayer player; if (Asset.PlaybackStyle == PHAssetPlaybackStyle.VideoLooping) { var queuePlayer = AVQueuePlayer.FromItems(new[] { playerItem }); playerLooper = AVPlayerLooper.FromPlayer(queuePlayer, playerItem); player = queuePlayer; } else { player = AVPlayer.FromPlayerItem(playerItem); } var playerLayer = AVPlayerLayer.FromPlayer(player); // Configure the AVPlayerLayer and add it to the view. playerLayer.VideoGravity = AVLayerVideoGravity.ResizeAspect; playerLayer.Frame = View.Layer.Bounds; View.Layer.AddSublayer(playerLayer); player.Play(); // Refer to the player layer so we can remove it later. this.playerLayer = playerLayer; }); }); } }