2

I'm using the UIImagePicker to pick only videos from my library and I set my media type to:

imagePicker.mediaTypes = [kUTTypeMovie as String]

I noticed that when the library is presented, even though I expect only videos, if there is a live photo in the library with a Bounce or Loop effect, it shows up also. If I take that same photo and switch it's effect to Live or Long Exposure it will no longer show up in the library. If I switch it back to Bounce or Loop it reappears.

I've tried both the .photoLibrary and the .savedPhotosAlbum and the same thing happens.

The reason I ask is because I want to keep them out of the library and I only want videos of xxx secs or more to be picked.

  1. Why do these effect types show up in the image picker library even though I'm picking video only?
  2. Why does only Loop and Bounce appear but Long Exposure and Live doesn't?
  3. How do I keep them out?

Maybe this would be a separate question but since it pertains to the same Live and Bounce photo issue I added it. I noticed that if I put a url that was derived from a Live or Bounce photo inside an AVPlayer, if I go to the background and come back there is a brief freeze when the app is back in the foreground, and it only happens with those 2 effects (which shouldn't be available). When the app goes to the background I remove the AVPlayerLayer correctly using this method Remove AVPlayerLayer but it's still briefly frozen (app is unresponsive) in the foreground when a url from those to effect types are initialized inside the player.

code:

import MobileCoreServices
import AVFoundation

class ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate{

var playerItem: AVPlayerItem?
var player: AVPlayer?
var playerLayer: AVPlayerLayer?
var currentPlayTime: CMTime?
let imagePicker = UIImagePickerController()

override func viewDidLoad() {
    super.viewDidLoad()

    imagePickerController.delegate = self

    NotificationCenter.default.addObserver(self, selector: #selector(appHasEnteredBackground), name: Notification.Name.UIApplicationWillResignActive, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground), name: Notification.Name.UIApplicationWillEnterForeground, object: nil)
}

override func viewDidLayoutSubviews() {
    // I have a UIView Outlet for the AVPlayerLayer named viewForPlayerLayer.

    guard let playerLayer = playerLayer else { return }
    playerLayer.videoGravity = .resizeAspectFill
    viewForPlayerLayer.layer.insertSublayer(playerLayer, at: 0)
    playerLayer.frame = viewForPlayerLayer.bounds
    playerLayer.masksToBounds = true

}

@IBAction fileprivate func showLibraryButtonTapped(_ sender: UIButton) {

    imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary // .savedPhotosAlbum also tried 
    imagePicker.mediaTypes = [kUTTypeMovie as String]
    imagePicker.videoMaximumDuration = 60
    present(imagePicker, animated: true, completion: nil)
}

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

    if let url = info[UIImagePickerControllerMediaURL] as? URL{

          let asset = AVAsset(url: url)
          playerItem = AVPlayerItem(asset: asset)
          player = AVPlayer(playerItem: playerItem!)
          playerLayer = AVPlayerLayer(player: player)
          player?.play()
    }
    imagePicker.dismiss(animated: true, completion: nil)
}

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    imagePicker.dismiss(animated: true, completion: nil)
}

@objc fileprivate func appHasEnteredBackground() {

    currentPlayTime = player.currentTime()

    if player.isPlaying{
        player.pause()
    }

    playerLayer = nil
}

@objc fileprivate func appWillEnterForeground(){

    if let player = player, let currentPlayTime = currentPlayTime{

        playerLayer = AVPlayerLayer(player: player)

        player.seek(to: currentPlayTime, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)
    }
}

}
picciano
  • 22,341
  • 9
  • 69
  • 82
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256
  • @matt hi, there are 2 issues here. 1. if those are actually photos, and I'm selecting [kUTTypeMovie as String] for videos only, why are they showing up inside the library at all? 2. If I choose the Bounce or Loop effect they show up as videos, but if I choose Live or Long Exposure they don't show up as video. It seems that even though they are photos, Live and Bounce effect converts them to videos – Lance Samaria Mar 21 '18 at 18:45
  • as always thanks for the help! – Lance Samaria Mar 21 '18 at 18:50

1 Answers1

1

You cannot prevent loop/bounce live photo videos appearing in the picker if you have asked to show videos, because they are videos. However, you can detect one if the user chooses one, in the delegate method. For this purpose, the UIImagePickerControllerMediaType is insufficiently fine-grained. Instead, get photo library authorization and get the PHAsset returned by the UIImagePickerControllerPHAsset key, and examine its playbackStyle. This will draw the distinctions you want.

https://developer.apple.com/documentation/photos/phasset.playbackstyle

.videoLooping is a bounce or zoom live photo.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • thanks, I thought [kUTTypeMovie as String] prevents anything that's not video. Can you answer the question on any the AVPlayer freezes when coming back from the background if it is initialized with these 2 types? – Lance Samaria Mar 21 '18 at 18:48
  • If I understand you correctly if the AVPlayer's url is a Live or Bounce type photo, then instead of using the AVPlayer I should use the AVQueuePlayer? – Lance Samaria Mar 21 '18 at 18:51
  • I have your iOS 10 book, I haven't upgraded to the 11 yet. It looks like I have to. Thanks for everything :) – Lance Samaria Mar 21 '18 at 18:52
  • I've followed your advice and I'm able to prevent the user from picking a live photo inside didFinishPickingMediaWithInfo. What is baffling me is when I go on to YouTube's iOS app, when i press the video icon to record, I only see movies in the library, none of the live photos appears. How did they prevent the library from presenting anything other then movies? Unless they use something different other then [kUTTypeMovie as String] ? – Lance Samaria Jun 12 '18 at 02:06
  • You mean like something custom or another api? – Lance Samaria Jun 12 '18 at 03:13
  • Lol . Thanks for advice. Writing a collectionView just for that seems like a lot of extra work. If people are using the app then I’d put in that effort otherwise I’ll stick with the imagePicker until my username goes up -substantially. Your github helped a ton though because even though they can choose a Live Photo, I can now prevent the image from being accessed. It saved me a ton of work. Thanks and goodnight. – Lance Samaria Jun 12 '18 at 03:40
  • hey, not sure if you remember this thread, but I asked you how does YouTube show only videos and not live photos when they present the user's library and you said I can write my own using a collectionView. When using PHAssest.fetchAssets() you can pick a media type of .video, .image, .unknown, or .audio. Would live photos show up with the .video option also? – Lance Samaria Sep 12 '18 at 00:32
  • Actually I followed the link you posted in the comments and it 100% worked although the live photos still appear and thanks to your code I can prevent them from picking one. What I want to figure out is how is it that the live photos don't show up at all. I'll post the question tomorrow using the current code I have (your code) and then ask from there. Thanks – Lance Samaria Sep 12 '18 at 01:11
  • I've used the fetchAssests for images, not videos (entirely different project). I'll run it with videos and sees what happens. If they don't show up then I'm good but if they do then I'll ask the question. Now that I think about it, I can use the asset.playbackstyle and see if it's a .livePhoto then just prevent them from being shown inside the collectionView. Yes that should work. Thanks for the hint :) – Lance Samaria Sep 12 '18 at 01:21
  • Maybe I need to ask the question then because i see as I use PHAsset.fetchAssets(with: .video, options: fetchOptions) and then once I get the asset I can run: if asset.playbackStyle == .livePhoto { // don't include }. It seems like your saying I can do that beforehand using the PHFetchOptions(). I don't see any options that provides the choice – Lance Samaria Sep 12 '18 at 01:25
  • Hey thanks, I found it :), I'm going to post the question anyway because I'm sure somebody somewhere in this big programming world of ours is going to need it. You should answer so you can get the credit. Please include your link :) https://stackoverflow.com/questions/52286312/swift-ios-how-to-exclude-livephotos-from-inclusion-in-phassets .Btw in the predicate I used PHAssetMediaSubtype.photoLive.rawValue – Lance Samaria Sep 12 '18 at 01:42