2016-02-09 13 views
7

मैं एक छवि और एक वीडियो को गठबंधन करने का प्रयास कर रहा हूं। मैंने उन्हें संयोजित और निर्यात किया है, हालांकि यह घुमावदार साइड तरीकों से घिरा हुआ है।AVFoundation निर्यात अभिविन्यास गलत

थोक कोड पेस्ट के लिए खेद है। मैंने compositionVideoTrack.preferredTransform में परिवर्तन को लागू करने के बारे में उत्तर देखा है, हालांकि यह कुछ भी नहीं करता है। AVMutableVideoCompositionInstruction में जोड़ना कुछ भी नहीं करता है।

मुझे ऐसा लगता है कि इस क्षेत्र में चीजें गलत होने लगती हैं। यहां यहां:

// I feel like this loading here is the problem 
     let videoTrack = videoAsset.tracksWithMediaType(AVMediaTypeVideo)[0] 

     // because it makes our parentLayer and videoLayer sizes wrong 
     let videoSize  = videoTrack.naturalSize 

     // this is returning 1920x1080, so it is rotating the video 
     print("\(videoSize.width) , \(videoSize.height)") 

तो यहां तक ​​कि हमारे फ्रेम आकार शेष विधि के लिए गलत हैं। अब जब हम ओवरले छवि परत को जाने और बनाने का प्रयास करते हैं तो फ्रेम सही नहीं है:

let aLayer = CALayer() 
    aLayer.contents = UIImage(named: "OverlayTestImageOverlay")?.CGImage 
    aLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height) 
    aLayer.opacity = 1 

यहां मेरी पूरी विधि है।

func combineImageVid() { 

     let path = NSBundle.mainBundle().pathForResource("SampleMovie", ofType:"MOV") 
     let fileURL = NSURL(fileURLWithPath: path!) 

     let videoAsset = AVURLAsset(URL: fileURL) 
     let mixComposition = AVMutableComposition() 

     let compositionVideoTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid) 

     var clipVideoTrack = videoAsset.tracksWithMediaType(AVMediaTypeVideo) 

     do { 
      try compositionVideoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAsset.duration), ofTrack: clipVideoTrack[0], atTime: kCMTimeZero) 
     } 
     catch _ { 
      print("failed to insertTimeRange") 
     } 


     compositionVideoTrack.preferredTransform = videoAsset.preferredTransform 

     // I feel like this loading here is the problem 
     let videoTrack = videoAsset.tracksWithMediaType(AVMediaTypeVideo)[0] 

     // because it makes our parentLayer and videoLayer sizes wrong 
     let videoSize  = videoTrack.naturalSize 

     // this is returning 1920x1080, so it is rotating the video 
     print("\(videoSize.width) , \(videoSize.height)") 

     let aLayer = CALayer() 
     aLayer.contents = UIImage(named: "OverlayTestImageOverlay")?.CGImage 
     aLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height) 
     aLayer.opacity = 1 


     let parentLayer  = CALayer() 
     let videoLayer  = CALayer() 

     parentLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height) 
     videoLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height) 

     parentLayer.addSublayer(videoLayer) 
     parentLayer.addSublayer(aLayer) 


     let videoComp = AVMutableVideoComposition() 
     videoComp.renderSize = videoSize 
     videoComp.frameDuration = CMTimeMake(1, 30) 
     videoComp.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, inLayer: parentLayer) 

     let instruction = AVMutableVideoCompositionInstruction() 

     instruction.timeRange = CMTimeRangeMake(kCMTimeZero, mixComposition.duration) 

     let mixVideoTrack = mixComposition.tracksWithMediaType(AVMediaTypeVideo)[0] 
     mixVideoTrack.preferredTransform = CGAffineTransformMakeRotation(CGFloat(M_PI * 90.0/180)) 

     let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: mixVideoTrack) 
     instruction.layerInstructions = [layerInstruction] 
     videoComp.instructions = [instruction] 


     // create new file to receive data 
     let dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) 
     let docsDir: AnyObject = dirPaths[0] 
     let movieFilePath = docsDir.stringByAppendingPathComponent("result.mov") 
     let movieDestinationUrl = NSURL(fileURLWithPath: movieFilePath) 

     do { 
      try NSFileManager.defaultManager().removeItemAtPath(movieFilePath) 
     } 
     catch _ {} 


     // use AVAssetExportSession to export video 
     let assetExport = AVAssetExportSession(asset: mixComposition, presetName:AVAssetExportPresetHighestQuality) 
     assetExport?.videoComposition = videoComp 
     assetExport!.outputFileType = AVFileTypeQuickTimeMovie 
     assetExport!.outputURL = movieDestinationUrl 
     assetExport!.exportAsynchronouslyWithCompletionHandler({ 
      switch assetExport!.status{ 
      case AVAssetExportSessionStatus.Failed: 
       print("failed \(assetExport!.error)") 
      case AVAssetExportSessionStatus.Cancelled: 
       print("cancelled \(assetExport!.error)") 
      default: 
       print("Movie complete") 


       // play video 
       NSOperationQueue.mainQueue().addOperationWithBlock({() -> Void in 
        print(movieDestinationUrl) 
       }) 
      } 
     }) 
    } 

यह है कि मैं क्या निर्यात हो रही है: enter image description here


मैं वीडियो बारी बारी से करने के लिए इन दोनों तरीकों जोड़ने का प्रयास:

class func videoCompositionInstructionForTrack(track: AVCompositionTrack, asset: AVAsset) -> AVMutableVideoCompositionLayerInstruction { 

    let instruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track) 

    let assetTrack = asset.tracksWithMediaType(AVMediaTypeVideo)[0] 

    let 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 
} 

class 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) 
} 

अद्यतन मेरी combineImageVid() विधि इसे

let instruction = AVMutableVideoCompositionInstruction() 

instruction.timeRange = CMTimeRangeMake(kCMTimeZero, mixComposition.duration) 

let mixVideoTrack = mixComposition.tracksWithMediaType(AVMediaTypeVideo)[0] 

//let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: mixVideoTrack) 
//layerInstruction.setTransform(videoAsset.preferredTransform, atTime: kCMTimeZero) 

let layerInstruction = videoCompositionInstructionForTrack(compositionVideoTrack, asset: videoAsset) 
में जोड़ना

कौन मुझे इस उत्पादन देता है:

enter image description here

तो मैं करीब हो रही है लेकिन मुझे लगता है कि क्योंकि ट्रैक मूल रूप से गलत तरीके से लोड किया जा रहा है, मैं वहाँ समस्या को हल करने की जरूरत है लग रहा है। इसके अलावा, मुझे नहीं पता कि अब विशाल ब्लैक बॉक्स क्यों है। मैं शायद सोचा था कि यह लोड वीडियो संपत्ति यहाँ की सीमा से ले रही है मेरी छवि परत की वजह से था:

aLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height) 

हालांकि कुछ छोटे चौड़ाई/ऊंचाई है कि बदलते एक फर्क नहीं है। मैं तो काला वर्ग से छुटकारा पाने के लिए एक फसल आरईसी जोड़ने के बारे में सोचा था, लेकिन है कि या तो काम नहीं किया :(


इन दोनों तरीकों का इस्तेमाल नहीं की Allens सुझाव के बाद:

class func videoCompositionInstructionForTrack(track: AVCompositionTrack, asset: AVAsset) -> AVMutableVideoCompositionLayerInstruction 

class func orientationFromTransform(transform: CGAffineTransform) -> (orientation: UIImageOrientation, isPortrait: Bool) 

लेकिन अद्यतन करने अपने मूल विधि इस तरह देखने के लिए:

videoLayer.frame = CGRectMake(0, 0, videoSize.height, videoSize.width) //notice the switched width and height 
... 
videoComp.renderSize = CGSizeMake(videoSize.height,videoSize.width) //this make the final video in portrait 
... 
layerInstruction.setTransform(videoTrack.preferredTransform, atTime: kCMTimeZero) //important piece of information let composition know you want to rotate the original video in output 

हम वास्तव में समाप्त होने वाला है लेकिन समस्या अब संपादन के लिए renderSize लगता है।अगर मैं परिदृश्य आकार के अलावा और कुछ के लिए इसे बदल मैं इस मिल:

enter image description here

+0

यहाँ इस लिंक से आपको मदद कर सकता है http://stackoverflow.com/questions/10034337/how-to- निर्यात-वीडियो-एसेट-थ्रू-एवासेटेटपोर्टेशन-इन-पोर्ट्रेट-मोड –

+0

मैंने यह भी कोशिश की है :(हालांकि मैं सुझाव की सराहना करता हूं। – random

+0

क्या आप इसे गठबंधन में बदलने की कोशिश कर सकते हैं ImageVid() विधि --- compositionVideoTrack.preferredTransform = CGAffineTransformMakeRotation (M_PI_2); –

उत्तर

14
यहाँ

एप्पल पर उन्मुखीकरण के लिए दस्तावेज है:

https://developer.apple.com/library/ios/qa/qa1744/_index.html

यदि अपने मूल वीडियो में लिया गया था पोर्ट्रेट मोड आईओएस, यह प्रकृति का आकार अभी भी परिदृश्य होगा, लेकिन यह mov फ़ाइल में घूमने के मेटाडेटा के साथ आता है। अपने वीडियो बारी बारी से करने में, आपको निम्न के साथ कोड के अपने 1 टुकड़ा में परिवर्तन करने की जरूरत है:

videoLayer.frame = CGRectMake(0, 0, videoSize.height, videoSize.width) //notice the switched width and height 
... 
videoComp.renderSize = CGSizeMake(videoSize.height,videoSize.width) //this make the final video in portrait 
... 
layerInstruction.setTransform(videoTrack.preferredTransform, atTime: kCMTimeZero) //important piece of information let composition know you want to rotate the original video in output 

हाँ, तुम सच में करीब हैं!

+0

मैं सहायता की सराहना करता हूं! हम हैं वास्तव में बंद हो रहा है हालांकि 'रेंडर आकार' को बदलते समय कोई समस्या हो रही है। मैंने क्या किया है इसके बारे में .gif के साथ कोई प्रश्न अपडेट किया है। – random

+0

@ यादृच्छिक, क्या आप सिम्युलेटर में चल रहे हैं? तो असली आईओएस डिवाइस में इसे चलाएं, सिम्युलेटर अनुवाद अच्छी तरह से नहीं कर सकता है। – Allen

+0

yup, सिम्युलेटर में इसे चलाने में समस्या थी! आप बहुत बढ़िया हैं, मदद के लिए बहुत बहुत धन्यवाद !! – random

0

शायद यू videoTrack के preferredTransform की जाँच करनी चाहिए ताकि यह एक सटीक renderSize देने के लिए और बदलने के लिए:

CGAffineTransform transform = assetVideoTrack.preferredTransform; 
CGFloat rotation = [self rotationWithTransform:transform]; 
//if been rotated 
     if (rotation != 0) 
     { 
      //if rotation is 360° 
      if (fabs((rotation - M_PI * 2)) >= valueOfError) { 

       CGFloat m = rotation/M_PI; 
       CGAffineTransform t1; 
       //rotation is 90° or 270° 
       if (fabs(m - 1/2.0) < valueOfError || fabs(m - 3/2.0) < valueOfError) { 
        self.mutableVideoComposition.renderSize = CGSizeMake(assetVideoTrack.naturalSize.height,assetVideoTrack.naturalSize.width); 
        t1 = CGAffineTransformMakeTranslation(assetVideoTrack.naturalSize.height, 0); 
       } 
       //rotation is 180° 
       if (fabs(m - 1.0) < valueOfError) { 
        t1 = CGAffineTransformMakeTranslation(assetVideoTrack.naturalSize.width, assetVideoTrack.naturalSize.height); 
       } 
       CGAffineTransform t2 = CGAffineTransformRotate(t1,rotation); 
       //    CGAffineTransform transform = makeTransform(1.0, 1.0, 90, videoTrack.naturalSize.height, 0); 
       [passThroughLayer setTransform:t2 atTime:kCMTimeZero]; 
      } 
     } 

//convert transform to radian 
- (CGFloat)rotationWithTransform:(CGAffineTransform)t 
{ 
    return atan2f(t.b, t.a); 
} 
+0

क्षमा करें, मैंने विस्तार का अनुवाद किया है। @ luk2302 – JohnChen

संबंधित मुद्दे