7

I want to perform an operation on a video in the iphone camera roll, and I require an absolute URI as I will be using ffmpeg natively within my app.

Is it possible to operate on the video in place? or would I need to copy the video to a tmp dir, operate on it, and then write back to the camera roll?

hunterp
  • 15,716
  • 18
  • 63
  • 115

3 Answers3

6

I've read some docs and tutorials and answering below based on that research.

Is it possible to operate on the video in place?

Yes (By copying it to temp dir) and No (to the original location where the video is actually stored)

Take a look at the following image and quote from official docs

enter image description here

Using PhotoKit, you can fetch and cache assets for display and playback, edit image and video content or manage collections of assets such as albums, Moments, and Shared Albums.

We don't have direct access to the location where the image/video is stored instead we get raw data or representation using PHAsset and Asset objects are immutable so we can't perform operations directly on it. We would need PHAssetChangeRequest to create, delete, change the metadata for, or edit the content of a Photos asset.

would I need to copy the video to a temp dir, operate on it, and then write back to the camera roll?

Yep, that's the way to go.

Sahil Manchanda
  • 9,812
  • 4
  • 39
  • 89
  • Of course a user can edit an image/video in place, the user will just be prompted with an alert telling them to confirm the changes. See the PHAsset class. – Celeste Feb 11 '20 at 06:08
  • 4
    @K4747Z Agreed. But with that, I meant directly to original location where the Video is actually stored. – Sahil Manchanda Feb 11 '20 at 06:14
  • But if we try to replace the edited video , when time of deleting un-edited video it will ask the permission to delete from `photos` , right ?......which may look odd, don't you think that ?? – Nayan Dave Feb 12 '20 at 11:14
  • 2
    @NayanDave we don't need to delete the original video. if you look at the PHAssetChangeRequest class they have mentioned "edit the content of Photos asset" and this is our case: edit the video. so the user will be prompted only once. – Sahil Manchanda Feb 12 '20 at 11:25
3

If you already fetched the assets, and have the PHFetchResult object try:

var video = PHAsset() // the video to be edited 

 if video.canPerform(.content) {  // check if the selected PHAsset can be edited

  video.requestContentEditingInput(with: nil, completionHandler: { editingInput, _ in

  let videoAsset = editingInput?.audiovisualAsset // get tracks and metadata of the video and start editing
  let videoURL = (videoAsset as? AVURLAsset)?.url // This might be nil so better use videoAsset

        /*
         Start editing your video here


        */

  guard let input = editingInput else { return }
  let output = PHContentEditingOutput(contentEditingInput: input)
  let outputURL = output.renderedContentURL // URL at which you write/export the edited video, it must be a .mov file
  let editedVideo = NSData()  // suppose your video fileName is editedVideo.mov, I used NSData since I don't know what final edited object will be.
  editedVideo.write(to: outputURL, atomically: false)

  PHPhotoLibrary.shared().performChanges({
  let changeRequest = PHAssetChangeRequest(for: video)
  changeRequest.contentEditingOutput = output
               })
            })

        }

Or if you're using default imagePicker, we can get tmp video url using:

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

    let videoURL = info[UIImagePickerController.InfoKey.mediaURL] as! NSURL
    print(videoURL)  // file is already in tmp folder


     let video = info[UIImagePickerController.InfoKey.phAsset] as! PHAsset
        // implement the above code using this PHAsset 

   // your will still need to request photo library changes, and save the edited video and/or delete the older one

    }
Celeste
  • 1,519
  • 6
  • 19
0

I implement something like this in my project I hope it will help you.

I show all the items in collection view and perform action on selection , you can also get the url of selected video

func getVideoFromCameraRoll() {
    let options = PHFetchOptions()
    options.sortDescriptors = [ NSSortDescriptor(key: "creationDate", ascending: false) ]
    options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.video.rawValue)
    videos = PHAsset.fetchAssets(with: options)
    videoLibraryCV.reloadData()
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return videos.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
    let asset = videos!.object(at: indexPath.row)
    let width: CGFloat = 150
    let height: CGFloat = 150
    let size = CGSize(width:width, height:height)
    cell.layer.borderWidth = 0.5
    cell.layer.borderColor = UIColor.lightGray.cgColor
    PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: PHImageContentMode.aspectFit, options: nil)
    {   (image, userInfo) -> Void in

        let imageView = cell.viewWithTag(1) as! UIImageView
        imageView.image = image

        let labelView = cell.viewWithTag(2) as! UILabel
        labelView.text = String(format: "%02d:%02d",Int((asset.duration / 60)),Int(asset.duration) % 60)
    }
    return cell
}

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
 let asset = photos!.object(at: indexPath.row)
 guard(asset.mediaType == PHAssetMediaType.Video)
 else {
  print("Not a valid video media type")
  return
 }

 PHCachingImageManager().requestAVAssetForVideo(asset, options: nil, resultHandler: {
  (asset: AVAsset ? , audioMix : AVAudioMix ? , info : [NSObject: AnyObject] ? ) in
  let asset = asset as!AVURLAsset
  print(asset.URL) // Here is video URL
 })

}

I hope it will work for you ...:)

Shivam Parmar
  • 1,520
  • 11
  • 27