2014-11-14 8 views
8

ich das Video am Erfassung UIImagePickerController verwendet wird, kann ich das Video beschneiden den folgenden Code verwenden,Platz Zuschneiden und Fixieren der Video Orientierung in iOS

AVAsset *asset = [AVAsset assetWithURL:url]; 

//create an avassetrack with our asset 
AVAssetTrack *clipVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 

//create a video composition and preset some settings 
AVMutableVideoComposition* videoComposition = [AVMutableVideoComposition videoComposition]; 
videoComposition.frameDuration = CMTimeMake(1, 30); 
//here we are setting its render size to its height x height (Square) 

videoComposition.renderSize = CGSizeMake(clipVideoTrack.naturalSize.height, clipVideoTrack.naturalSize.height); 

//create a video instruction 
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; 
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30)); 

AVMutableVideoCompositionLayerInstruction* transformer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack]; 

//Here we shift the viewing square up to the TOP of the video so we only see the top 
CGAffineTransform t1 = CGAffineTransformMakeTranslation(clipVideoTrack.naturalSize.height, -20); 

//Use this code if you want the viewing square to be in the middle of the video 
//CGAffineTransform t1 = CGAffineTransformMakeTranslation(clipVideoTrack.naturalSize.height, -(clipVideoTrack.naturalSize.width - clipVideoTrack.naturalSize.height) /2); 

//Make sure the square is portrait 
CGAffineTransform t2 = CGAffineTransformRotate(t1, M_PI_2); 

CGAffineTransform finalTransform = t2; 
[transformer setTransform:finalTransform atTime:kCMTimeZero]; 

//add the transformer layer instructions, then add to video composition 
instruction.layerInstructions = [NSArray arrayWithObject:transformer]; 
videoComposition.instructions = [NSArray arrayWithObject: instruction]; 

//Create an Export Path to store the cropped video 
NSString *outputPath = [NSString stringWithFormat:@"%@%@", NSTemporaryDirectory(), @"video.mp4"]; 
NSURL *exportUrl = [NSURL fileURLWithPath:outputPath]; 

//Remove any prevouis videos at that path 
[[NSFileManager defaultManager] removeItemAtURL:exportUrl error:nil]; 

//Export  
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetLowQuality] ; 
exporter.videoComposition = videoComposition; 
exporter.outputURL = exportUrl; 
exporter.outputFileType = AVFileTypeMPEG4; 

[exporter exportAsynchronouslyWithCompletionHandler:^ 
{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     //Call when finished 
     [self exportDidFinish:exporter]; 
    }); 
}]; 

Aber ich weiß nicht, wie die Ausrichtung Problem zu beheben. Wie Instagram und Reben App, (d. H. Wenn ich das Video auch im Querformat aufnehmen soll, sollte es im Hochformat sein und das Video als Quadrat zuschneiden. Pls geben Sie mir die Lösung ... ich mit diesem Thema habe Schwierigkeiten ...

+0

hey, ich bin den Code in der Antwort verwenden, hätte meine Ernte arbeiten, aber ich sehe diese seltsame grüne Kontur um den Boden und die rechte Seite, haben Sie dieses Problem gehabt? – iqueqiorio

Antwort

21

Ich nehme an, den Quellcode kommen aus diesem Link (Projektcode enthalten)

http://www.one-dreamer.com/cropping-video-square-like-vine-instagram-xcode/

Sie müssen zuerst die wissen REAL Video Orientierung:

- (UIImageOrientation)getVideoOrientationFromAsset:(AVAsset *)asset 
{ 
    AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 
    CGSize size = [videoTrack naturalSize]; 
    CGAffineTransform txf = [videoTrack preferredTransform]; 

    if (size.width == txf.tx && size.height == txf.ty) 
     return UIImageOrientationLeft; //return UIInterfaceOrientationLandscapeLeft; 
    else if (txf.tx == 0 && txf.ty == 0) 
     return UIImageOrientationRight; //return UIInterfaceOrientationLandscapeRight; 
    else if (txf.tx == 0 && txf.ty == size.width) 
     return UIImageOrientationDown; //return UIInterfaceOrientationPortraitUpsideDown; 
    else 
     return UIImageOrientationUp; //return UIInterfaceOrientationPortrait; 
} 

habe ich diese Funktion in einer Weise, dass es die richtige Orientierung zurückzukehren, als ob es ein Bild war

Dann modifizierte i die Funktion, die richtige Orientierung zu fixieren, jede Ernte Region unterstützte nicht nur einen Platz, wie folgt aus:

// apply the crop to passed video asset (set outputUrl to avoid the saving on disk). Return the exporter session object 
- (AVAssetExportSession*)applyCropToVideoWithAsset:(AVAsset*)asset AtRect:(CGRect)cropRect OnTimeRange:(CMTimeRange)cropTimeRange ExportToUrl:(NSURL*)outputUrl ExistingExportSession:(AVAssetExportSession*)exporter WithCompletion:(void(^)(BOOL success, NSError* error, NSURL* videoUrl))completion 
{ 

    //create an avassetrack with our asset 
    AVAssetTrack *clipVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 

    //create a video composition and preset some settings 
    AVMutableVideoComposition* videoComposition = [AVMutableVideoComposition videoComposition]; 
    videoComposition.frameDuration = CMTimeMake(1, 30); 

    CGFloat cropOffX = cropRect.origin.x; 
    CGFloat cropOffY = cropRect.origin.y; 
    CGFloat cropWidth = cropRect.size.width; 
    CGFloat cropHeight = cropRect.size.height; 

    videoComposition.renderSize = CGSizeMake(cropWidth, cropHeight); 

    //create a video instruction 
    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; 
    instruction.timeRange = cropTimeRange; 

    AVMutableVideoCompositionLayerInstruction* transformer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack]; 

    UIImageOrientation videoOrientation = [self getVideoOrientationFromAsset:asset]; 

    CGAffineTransform t1 = CGAffineTransformIdentity; 
    CGAffineTransform t2 = CGAffineTransformIdentity; 

    switch (videoOrientation) { 
     case UIImageOrientationUp: 
      t1 = CGAffineTransformMakeTranslation(clipVideoTrack.naturalSize.height - cropOffX, 0 - cropOffY); 
      t2 = CGAffineTransformRotate(t1, M_PI_2); 
      break; 
     case UIImageOrientationDown: 
      t1 = CGAffineTransformMakeTranslation(0 - cropOffX, clipVideoTrack.naturalSize.width - cropOffY); // not fixed width is the real height in upside down 
      t2 = CGAffineTransformRotate(t1, - M_PI_2); 
      break; 
     case UIImageOrientationRight: 
      t1 = CGAffineTransformMakeTranslation(0 - cropOffX, 0 - cropOffY); 
      t2 = CGAffineTransformRotate(t1, 0); 
      break; 
     case UIImageOrientationLeft: 
      t1 = CGAffineTransformMakeTranslation(clipVideoTrack.naturalSize.width - cropOffX, clipVideoTrack.naturalSize.height - cropOffY); 
      t2 = CGAffineTransformRotate(t1, M_PI ); 
      break; 
     default: 
      NSLog(@"no supported orientation has been found in this video"); 
      break; 
    } 

    CGAffineTransform finalTransform = t2; 
    [transformer setTransform:finalTransform atTime:kCMTimeZero]; 

    //add the transformer layer instructions, then add to video composition 
    instruction.layerInstructions = [NSArray arrayWithObject:transformer]; 
    videoComposition.instructions = [NSArray arrayWithObject: instruction]; 

    //Remove any prevouis videos at that path 
    [[NSFileManager defaultManager] removeItemAtURL:outputUrl error:nil]; 

    if (!exporter){ 
     exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality] ; 
    } 

    // assign all instruction for the video processing (in this case the transformation for cropping the video 
    exporter.videoComposition = videoComposition; 
    //exporter.outputFileType = AVFileTypeQuickTimeMovie; 

    if (outputUrl){ 

     exporter.outputURL = outputUrl; 
     [exporter exportAsynchronouslyWithCompletionHandler:^{ 

      switch ([exporter status]) { 
       case AVAssetExportSessionStatusFailed: 
        NSLog(@"crop Export failed: %@", [[exporter error] localizedDescription]); 
        if (completion){ 
         dispatch_async(dispatch_get_main_queue(), ^{ 
          completion(NO,[exporter error],nil); 
         }); 
         return; 
        } 
        break; 
       case AVAssetExportSessionStatusCancelled: 
        NSLog(@"crop Export canceled"); 
        if (completion){ 
         dispatch_async(dispatch_get_main_queue(), ^{ 
          completion(NO,nil,nil); 
         }); 
         return; 
        } 
        break; 
       default: 
        break; 
      } 

      if (completion){ 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        completion(YES,nil,outputUrl); 
       }); 
      } 

     }]; 
    } 

    return exporter; 
} 

Getestet in alle aufgezeichneten Videoausrichtung (oben, unten, Lanscape R, Landschaft L) in sowohl normale als auch vordere Kamerataschen. Getestet habe ich es auf dem iPhone 5S (iOS 8.1), iPhone 6 Plus (iOS 8.1)

Hoffe, dass es

+0

Danke ... es funktioniert gut .. aber nur das Problem ist, setze ich cropOffY = 60 .. wenn im Querformat aufnehmen, ist das Video abgeschnitten nicht korrekt auch dort ist ein schwarzer Bereich im unteren Teil des Videos angezeigt. Lassen Sie mich wissen, wie Sie dieses Problem beheben können? – Surfer

+0

Ich reparierte das oben genannte Problem .. aber wenn ich Video von der Foto-Bibliothek wähle, schaut das gekürzte Video gezoomt herein. Pls ließ wissen, wie man dieses Problem löst – Surfer

+0

Scheint seltsam, da es keine direkte Skalierung auf dem Video anwendet, es definiert nur den Renderbereich, und für die Ausrichtung dreht und übersetzt er einfach. Was können Sie versuchen, den Maßstab auf 1: 1 wie folgt einzustellen: t2 = CGAffineTransformScale (t1, 1, 1) dann t2 = CGAffineTransformRotate (t2, M_PI_2); (Dies ist für den ersten Fall im Schaltblock, und so für alle Fälle), aber ich denke nicht, dass es sich ändert. Vielleicht könnte die Tatsache sein, dass wenn man ein Video vom Picker nimmt, es komprimiert ist. Wenn Sie ein Video von der Auswahl nehmen, gehen sie von 1920x1080 zu 1280x720 für den AVAsset (video.naturalSize) über. –

5

hilft Ich weiß, diese Frage ist alt, aber einige Leute immer noch fragen können, warum von der Kamera einige der Videos Zoomen Sie ein, nachdem Sie abgeschnitten wurden. Ich stellte dieses Problem und erkannte, dass der cropRect, den ich als Frame verwendete, nicht für die verschiedenen Seitenverhältnisse des Videos skaliert wurde. Um dieses Problem zu beheben, habe ich einfach den folgenden Code hinzugefügt, um den oberen Rand des Videos in ein Quadrat zu schneiden. Wenn Sie die Position ändern möchten, ändern Sie einfach den y-Wert, aber stellen Sie sicher, dass Sie ihn entsprechend dem Video skalieren. Luca Iaco lieferte einen guten Code für den Einstieg. Ich schätze es!

CGSize videoSize = [[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] naturalSize]; 
float scaleFactor; 

if (videoSize.width > videoSize.height) { 

    scaleFactor = videoSize.height/320; 
} 
else if (videoSize.width == videoSize.height){ 

    scaleFactor = videoSize.height/320; 
} 
else{ 
    scaleFactor = videoSize.width/320; 
} 

CGFloat cropOffX = 0; 
CGFloat cropOffY = 0; 
CGFloat cropWidth = 320 *scaleFactor; 
CGFloat cropHeight = 320 *scaleFactor; 
4

Dies ist mein Code, um ein rebenartiges Video aus einem Video auf der Festplatte zu erstellen. Dies ist in swift geschrieben:

static let MaxDuration: CMTimeValue = 12 

class func compressVideoAsset(_ asset: AVAsset, output: URL, completion: @escaping (_ data: Data?) -> Void) 
{ 
    let session = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetMediumQuality)! 
    session.videoComposition = self.squareVideoCompositionForAsset(asset) 
    session.outputURL = output 
    session.outputFileType = AVFileTypeMPEG4 
    session.shouldOptimizeForNetworkUse = true 
    session.canPerformMultiplePassesOverSourceMediaData = true 

    let duration = CMTimeValue(CGFloat(asset.duration.value)/CGFloat(asset.duration.timescale) * 30) 
    session.timeRange = CMTimeRange(start: kCMTimeZero, duration: CMTime(value: min(duration, VideoCompressor.MaxDuration * 30), timescale: 30)) 

    session.exportAsynchronously(completionHandler: {() -> Void in 
     let data = try? Data(contentsOf: output) 

     DispatchQueue.main.async(execute: {() -> Void in 
      completion(data) 
     }) 
    }) 
} 

private class func squareVideoCompositionForAsset(_ asset: AVAsset) -> AVVideoComposition 
{ 
    let track = asset.tracks(withMediaType: AVMediaTypeVideo)[0] 
    let length = min(track.naturalSize.width, track.naturalSize.height) 

    var transform = track.preferredTransform 

    let size = track.naturalSize 
    let scale: CGFloat = (transform.a == -1 && transform.b == 0 && transform.c == 0 && transform.d == -1) ? -1 : 1 // check for inversion 

    transform = transform.translatedBy(x: scale * -(size.width - length)/2, y: scale * -(size.height - length)/2) 

    let transformer = AVMutableVideoCompositionLayerInstruction(assetTrack: track) 
    transformer.setTransform(transform, at: kCMTimeZero) 

    let instruction = AVMutableVideoCompositionInstruction() 
    instruction.timeRange = CMTimeRange(start: kCMTimeZero, duration: kCMTimePositiveInfinity) 
    instruction.layerInstructions = [transformer] 

    let composition = AVMutableVideoComposition() 
    composition.frameDuration = CMTime(value: 1, timescale: 30) 
    composition.renderSize = CGSize(width: length, height: length) 
    composition.instructions = [instruction] 

    return composition 
} 
+0

Bitte werfen Sie einen Blick auf [meine Frage] (http://stackoverflow.com/questions/43558021/swift-square-video-composition) –

+0

Hi pigeon_39. Ich habe meinen obigen Code bearbeitet. Ich glaube, ich habe das gleiche Rotationsproblem bekommen, und diese aktualisierte Logik sollte es beheben. –

+0

danke. Es funktionierte perfekt für Landschaftsvideo, aber nicht für Hochformat. Kannst du mir bitte ein bisschen helfen? Das ist meine [aktualisierte Frage] (http://stackoverflow.com/questions/43558021/swift-square-video-composition) –