Swift 3: How to add watermark on video ? AVVideoCompositionCoreAnimationTool iOS 10 issue -


this code used work on ios9 add watermark , text video since ios10 it's not working anymore. there ios 10 bug has been filed no answer apple. have not been able implement workaround add watermark , text on video. code times video exported of time won't exported.

how should use avvideocompositioncoreanimationtool works did on ios9.

let videocomposition: avmutablevideocomposition = avmutablevideocomposition()  videocomposition.frameduration = cmtimemake(1, 60) videocomposition.rendersize = cgsize(width: clipvideotrack.naturalsize.height, height: clipvideotrack.naturalsize.height)   let instruction: avmutablevideocompositioninstruction = avmutablevideocompositioninstruction()  instruction.timerange = cmtimerangemake(kcmtimezero, cmtimemakewithseconds(60, 30))  // transformer applied set video in portrait otherwise rotated 90 degrees let transformer: avmutablevideocompositionlayerinstruction =     avmutablevideocompositionlayerinstruction(assettrack: clipvideotrack)  let t1: cgaffinetransform = cgaffinetransform(translationx: clipvideotrack.naturalsize.height, y: -(clipvideotrack.naturalsize.width - clipvideotrack.naturalsize.height)/2)  let t2: cgaffinetransform = t1.rotated(by: cgfloat(m_pi_2))  var finaltransform: cgaffinetransform = t2  transformer.settransform(finaltransform, at: kcmtimezero)  instruction.layerinstructions = nsarray(object: transformer) as! [avvideocompositionlayerinstruction]  videocomposition.instructions = nsarray(object: instruction) as! [avvideocompositioninstructionprotocol]    let mixcomposition = avmutablecomposition() let compositionvideotrack = mixcomposition.addmutabletrack(withmediatype: avmediatypevideo, preferredtrackid: kcmpersistenttrackid_invalid)   {     try compositionvideotrack.inserttimerange(cmtimerangemake(kcmtimezero, asset.duration), of: clipvideotrack, at: kcmtimezero) } catch {     print(error) }   //add watermark   let myimage = uiimage(named: "logo")  let alayer = calayer() alayer.contents = myimage!.cgimage alayer.frame = cgrect(x: (clipvideotrack.naturalsize.height*(self.view.bounds.width-45))/self.view.bounds.width, y: (clipvideotrack.naturalsize.height*(self.view.bounds.width-40))/self.view.bounds.width, width: (clipvideotrack.naturalsize.height*40)/self.view.bounds.width, height: (clipvideotrack.naturalsize.height*40)/self.view.bounds.width)  let titlelayer = catextlayer() titlelayer.string = "text" titlelayer.font = uifont(name: "helvetica", size: 0) titlelayer.fontsize = clipvideotrack.naturalsize.height/16 titlelayer.shadowopacity = 0.5 titlelayer.alignmentmode = kcaalignmentcenter titlelayer.frame = cgrect(x: 0, y: 0, width: clipvideotrack.naturalsize.height, height: clipvideotrack.naturalsize.height/6) titlelayer.display()   let videosize = asset.tracks(withmediatype: avmediatypevideo)[0].naturalsize let parentlayer = calayer() let videolayer = calayer() parentlayer.frame = cgrect(x: 0, y: 0, width: videosize.height, height: videosize.height) videolayer.frame = cgrect(x: 0, y: 0, width: videosize.height, height: videosize.height)  parentlayer.addsublayer(videolayer) parentlayer.addsublayer(alayer) parentlayer.addsublayer(titlelayer)   videocomposition.animationtool = avvideocompositioncoreanimationtool(postprocessingasvideolayer: videolayer, in: parentlayer)    { try filemanager.default.removeitem(at: filepath) } catch let error nserror {     nslog("\(error), \(error.localizeddescription)") }    var exporturl: url = filepath self.videourl = filepath nsurl   var exporter = avassetexportsession(asset: asset, presetname: avassetexportpresetmediumquality)  exporter!.videocomposition = videocomposition exporter!.outputfiletype = avfiletypequicktimemovie exporter!.outputurl = url(fileurlwithpath: exporturl.path)   exporter!.exportasynchronously(completionhandler: {      dispatchqueue.main.async {           self.view.layer.addsublayer(self.avplayerlayer)          let item = avplayeritem(url: exporturl)         self.player.replacecurrentitem(with: item)          if (self.player.currentitem != nil) {             print("starting playback!")             self.player.play()         }      }  }) 

please note: if remove avvideocompositioncoreanimationtool video exported ,hans no watermark , text on video. how make work avvideocompositioncoreanimationtool not conflict avassetexportsession ?

some have implemented workaround customvideocompositorclass , avvideocompositing protocol seems heavy workaround compared how used work.

i have got answer here , working me. see if working you.

import uikit import assetslibrary import avfoundation  enum quwatermarkposition {     case topleft     case topright     case bottomleft     case bottomright     case default }  class quwatermarkmanager: nsobject {      func watermark(video videoasset:avasset, watermarktext text : string, savetolibrary flag : bool, watermarkposition position : quwatermarkposition, completion : ((status : avassetexportsessionstatus!, session: avassetexportsession!, outputurl : nsurl!) -> ())?) {         self.watermark(video: videoasset, watermarktext: text, imagename: nil, savetolibrary: flag, watermarkposition: position) { (status, session, outputurl) -> () in             completion!(status: status, session: session, outputurl: outputurl)         }     }      func watermark(video videoasset:avasset, imagename name : string, savetolibrary flag : bool, watermarkposition position : quwatermarkposition, completion : ((status : avassetexportsessionstatus!, session: avassetexportsession!, outputurl : nsurl!) -> ())?) {         self.watermark(video: videoasset, watermarktext: nil, imagename: name, savetolibrary: flag, watermarkposition: position) { (status, session, outputurl) -> () in             completion!(status: status, session: session, outputurl: outputurl)         }     }      private func watermark(video videoasset:avasset, watermarktext text : string!, imagename name : string!, savetolibrary flag : bool, watermarkposition position : quwatermarkposition, completion : ((status : avassetexportsessionstatus!, session: avassetexportsession!, outputurl : nsurl!) -> ())?) {          dispatch_async(dispatch_get_global_queue(dispatch_queue_priority_default, 0), { () -> void in             var mixcomposition = avmutablecomposition()              var compositionvideotrack = mixcomposition.addmutabletrackwithmediatype(avmediatypevideo, preferredtrackid: int32(kcmpersistenttrackid_invalid))             var clipvideotrack = videoasset.trackswithmediatype(avmediatypevideo)[0] as! avassettrack             compositionvideotrack.inserttimerange(cmtimerangemake(kcmtimezero, videoasset.duration), oftrack: clipvideotrack, attime: kcmtimezero, error: nil)             clipvideotrack.preferredtransform              let videosize = clipvideotrack.naturalsize              var parentlayer = calayer()             var videolayer = calayer()             parentlayer.frame = cgrectmake(0, 0, videosize.width, videosize.height)             videolayer.frame = cgrectmake(0, 0, videosize.width, videosize.height)             parentlayer.addsublayer(videolayer)              if text != nil {                 var titlelayer = catextlayer()                 titlelayer.backgroundcolor = uicolor.redcolor().cgcolor                 titlelayer.string = text                 titlelayer.font = "helvetica"                 titlelayer.fontsize = 15                 titlelayer.alignmentmode = kcaalignmentcenter                 titlelayer.bounds = cgrectmake(0, 0, videosize.width, videosize.height)                 parentlayer.addsublayer(titlelayer)             } else if name != nil {                 var watermarkimage = uiimage(named: name)                 var imagelayer = calayer()                 imagelayer.contents = watermarkimage?.cgimage                  var xposition : cgfloat = 0.0                 var yposition : cgfloat = 0.0                 let imagesize : cgfloat = 57.0                  switch (position) {                 case .topleft:                     xposition = 0                     yposition = 0                     break                 case .topright:                     xposition = videosize.width - imagesize                     yposition = 0                     break                 case .bottomleft:                     xposition = 0                     yposition = videosize.height - imagesize                     break                 case .bottomright, .default:                     xposition = videosize.width - imagesize                     yposition = videosize.height - imagesize                     break                 default:                     break                 }                   imagelayer.frame = cgrectmake(xposition, yposition, imagesize, imagesize)                 imagelayer.opacity = 0.65                 parentlayer.addsublayer(imagelayer)             }              var videocomp = avmutablevideocomposition()             videocomp.rendersize = videosize             videocomp.frameduration = cmtimemake(1, 30)             videocomp.animationtool = avvideocompositioncoreanimationtool(postprocessingasvideolayer: videolayer, inlayer: parentlayer)              var instruction = avmutablevideocompositioninstruction()             instruction.timerange = cmtimerangemake(kcmtimezero, mixcomposition.duration)             var videotrack = mixcomposition.trackswithmediatype(avmediatypevideo)[0] as! avassettrack              let layerinstruction = self.videocompositioninstructionfortrack(compositionvideotrack, asset: videoasset)              instruction.layerinstructions = [layerinstruction]             videocomp.instructions = [instruction]              let documentdirectory = nssearchpathfordirectoriesindomains(.documentdirectory, .userdomainmask, true)[0] as! string             var dateformatter = nsdateformatter()             dateformatter.datestyle = .longstyle             dateformatter.timestyle = .shortstyle             let date = dateformatter.stringfromdate(nsdate())             let savepath = documentdirectory.stringbyappendingpathcomponent("watermarkvideo-\(date).mov")             let url = nsurl(fileurlwithpath: savepath)              let exporter = avassetexportsession(asset: mixcomposition, presetname: avassetexportpresethighestquality)             exporter.outputurl = url             exporter.outputfiletype = avfiletypequicktimemovie             exporter.shouldoptimizefornetworkuse = true             exporter.videocomposition = videocomp              exporter.exportasynchronouslywithcompletionhandler() {                 dispatch_async(dispatch_get_main_queue(), { () -> void in                     if exporter.status == avassetexportsessionstatus.completed {                         let outputurl = exporter.outputurl                         if flag {                             // save library                             let library = alassetslibrary()                             if library.videoatpathiscompatiblewithsavedphotosalbum(outputurl) {                                 library.writevideoatpathtosavedphotosalbum(outputurl,                                     completionblock: { (asseturl:nsurl!, error:nserror!) -> void in                                         completion!(status: avassetexportsessionstatus.completed, session: exporter, outputurl: outputurl)                                 })                             }                         } else {                             completion!(status: avassetexportsessionstatus.completed, session: exporter, outputurl: outputurl)                         }                      } else {                         // error                         completion!(status: exporter.status, session: exporter, outputurl: nil)                     }                 })             }         })     }       private func orientationfromtransform(transform: cgaffinetransform) -> (orientation: uiimageorientation, isportrait: bool) {         var assetorientation = uiimageorientation.up         var isportrait = false         if transform.a == 0 && transform.b == 1.0 && transform.c == -1.0 && transform.d == 0 {             assetorientation = .right             isportrait = true         } else if transform.a == 0 && transform.b == -1.0 && transform.c == 1.0 && transform.d == 0 {             assetorientation = .left             isportrait = true         } else if transform.a == 1.0 && transform.b == 0 && transform.c == 0 && transform.d == 1.0 {             assetorientation = .up         } else if transform.a == -1.0 && transform.b == 0 && transform.c == 0 && transform.d == -1.0 {             assetorientation = .down         }         return (assetorientation, isportrait)     }      private func videocompositioninstructionfortrack(track: avcompositiontrack, asset: avasset) -> avmutablevideocompositionlayerinstruction {         let instruction = avmutablevideocompositionlayerinstruction(assettrack: track)         let assettrack = asset.trackswithmediatype(avmediatypevideo)[0] as! avassettrack          var transform = assettrack.preferredtransform         let assetinfo = orientationfromtransform(transform)          var scaletofitratio = uiscreen.mainscreen().bounds.width / assettrack.naturalsize.width         if assetinfo.isportrait {             scaletofitratio = uiscreen.mainscreen().bounds.width / assettrack.naturalsize.height             let scalefactor = cgaffinetransformmakescale(scaletofitratio, scaletofitratio)             instruction.settransform(cgaffinetransformconcat(assettrack.preferredtransform, scalefactor),                 attime: kcmtimezero)         } else {             let scalefactor = cgaffinetransformmakescale(scaletofitratio, scaletofitratio)             var concat = cgaffinetransformconcat(cgaffinetransformconcat(assettrack.preferredtransform, scalefactor), cgaffinetransformmaketranslation(0, uiscreen.mainscreen().bounds.width / 2))             if assetinfo.orientation == .down {                 let fixupsidedown = cgaffinetransformmakerotation(cgfloat(m_pi))                 let windowbounds = uiscreen.mainscreen().bounds                 let yfix = assettrack.naturalsize.height + windowbounds.height                 let centerfix = cgaffinetransformmaketranslation(assettrack.naturalsize.width, yfix)                 concat = cgaffinetransformconcat(cgaffinetransformconcat(fixupsidedown, centerfix), scalefactor)             }             instruction.settransform(concat, attime: kcmtimezero)         }          return instruction     } } 

Comments

Popular posts from this blog

asynchronous - C# WinSCP .NET assembly: How to upload multiple files asynchronously -

aws api gateway - SerializationException in posting new Records via Dynamodb Proxy Service in API -

asp.net - Problems sending emails from forum -