2015-06-09 43 views
1

我想拍攝一個視頻(例如:用iPhone拍攝16:9照片),並將其放置在具有自定義背景色的正方形中。我的代碼如下:用AVFoundation創建一個帶有自定義背景色和寬高比的視頻的方形視頻

- (void)videoOutput 
{ 
    if (!self.firstAsset) { 
     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Please Load a Video Asset First" 
                 delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; 
     [alert show]; 
     return; 
    } 

    AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init]; 

    AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo 
                     preferredTrackID:kCMPersistentTrackID_Invalid]; 
    [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, self.firstAsset.duration) 
         ofTrack:[[self.firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] 
         atTime:kCMTimeZero error:nil]; 

    AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; 
    mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, self.firstAsset.duration); 

    AVMutableVideoCompositionLayerInstruction *videolayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack]; 
    AVAssetTrack *videoAssetTrack = [[self.firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 

    CGSize videoSize = [[[firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] naturalSize]; 
    NSLog(@"Video Size W:%f, H:%f",videoSize.width,videoSize.height); 

    float scaleRatio = 600/videoSize.width; 

    [videolayerInstruction setTransform:CGAffineTransformMakeScale(scaleRatio, scaleRatio) atTime:kCMTimeZero]; 
    [videolayerInstruction setOpacity:0.0 atTime:self.firstAsset.duration]; 

    mainInstruction.layerInstructions = [NSArray arrayWithObjects:videolayerInstruction,nil]; 

    AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition]; 

    float renderWidth, renderHeight; 
    renderWidth = 600; 
    renderHeight = 600; 
    mainCompositionInst.renderSize = CGSizeMake(renderWidth, renderHeight); 
    mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction]; 
    mainCompositionInst.frameDuration = CMTimeMake(1, 30); 

    [self applyVideoEffectsToComposition:mainCompositionInst size:CGSizeMake(600, 600)]; 

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; 
    NSString *myPathDocs = [documentsDirectory stringByAppendingPathComponent: 
          [NSString stringWithFormat:@"FinalVideo-%d.mov",arc4random() % 1000]]; 
    NSURL *url = [NSURL fileURLWithPath:myPathDocs]; 

    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition 
                     presetName:AVAssetExportPresetHighestQuality]; 
    exporter.outputURL=url; 
    exporter.outputFileType = AVFileTypeQuickTimeMovie; 
    exporter.shouldOptimizeForNetworkUse = YES; 
    exporter.videoComposition = mainCompositionInst; 
    [exporter exportAsynchronouslyWithCompletionHandler:^{ 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self exportDidFinish:exporter]; 
     }); 
    }]; 
} 



- (void)applyVideoEffectsToComposition:(AVMutableVideoComposition *)composition size:(CGSize)size 
{ 
    UIImage *borderImage = nil; 

    borderImage = [self imageWithColor:[UIColor greenColor] rectSize:CGRectMake(0, 0, size.width, size.height)]; 


    CALayer *backgroundLayer = [CALayer layer]; 
    [backgroundLayer setContents:(id)[borderImage CGImage]]; 
    backgroundLayer.frame = CGRectMake(0, 0, size.width, size.height); 
    [backgroundLayer setMasksToBounds:YES]; 



    AVPlayerItem *playerItem2 = [[AVPlayerItem alloc] initWithAsset:secondAsset]; 

    AVPlayer *videoPlayer2 = [AVPlayer playerWithPlayerItem:playerItem2]; 
    AVPlayerLayer *videoLayer = [AVPlayerLayer playerLayerWithPlayer:videoPlayer2]; 
    CGSize videoSize = [[[secondAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] naturalSize]; 

    [videoLayer setBackgroundColor:[UIColor whiteColor].CGColor]; 
    videoLayer.frame = CGRectMake(0, (600-337.5)/2, 600, 337.5); 
    CALayer *parentLayer = [CALayer layer]; 
    parentLayer.frame = CGRectMake(0, 0, size.width, size.height); 
    [parentLayer addSublayer:backgroundLayer]; 
    [parentLayer addSublayer:videoLayer]; 

    composition.animationTool = [AVVideoCompositionCoreAnimationTool 
           videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer]; 
} 

原始視頻和導出的結果如下圖所示。正如您在導出的視頻中看到的那樣,覆蓋視頻的幀是正確的。但其中的視頻不能保持其寬高比。如果我選擇使錄像機畫面呈方形,則縱橫比保持正常。

Original Video (1920x1080) Cropped video (600x600) with original video overlaid.

我停留在早期的水平。最終,我正在嘗試爲方形視頻構建所見即所得編輯器,並將縮放,平移和旋轉轉換應用到將在方形視頻中呈現的視頻圖層。任何有關這個具體問題和前鋒的幫助都非常感謝。

+0

我現在遇到了同樣的問題。任何解決方案? –

回答

1

這正是我所經歷的。現在我有一個解決方案。如果您想將視頻從矩形形狀更改爲方形。您需要裁剪視頻並將AVMutableVideoCompositionInstruction的backgroundColor設置爲所需的顏色。

  1. 確認視頻的'UIImageOrientation'。
  2. 按'videoComposition.renderSize'裁剪視頻,renderSize.width等於renderSize.height。 renderSize.width是原始視頻大小的一側。
  3. AVMutableVideoCompositionInstruction * instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];

instruction.backgroundColor =/CGColorRef /;

Apple報價:

/*表示構圖的背景顏色。僅支持固體BGRA顏色;不支持的圖案和其他顏色參考將被忽略。 如果未指定背景顏色,則視頻合成器將使用不透明黑色的默認backgroundColor。 如果渲染的像素緩衝區沒有alpha,則backgroundColor的alpha值將被忽略。 */ @property(nonatomic,retain,nullable)屬性((NSObject))CGColorRef backgroundColor CF_RETURNS_RETAINED;

錯誤的方式來設定指令的backgroundColor是:

instruction.backgroundColor = [的UIColor blueColor] .CGColor;

正確之一是:

CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB(); 
    const CGFloat myColor[] = {1.0, 1.0, 1.0, 1.0}; //white 
    CGColorRef ref = CGColorCreate(rgb, myColor); 
    instruction.backgroundColor = ref; 
  • 導出視頻。
  • 完成!

    順便說一下,videolayer和videoComposition.renderSize必須設置原始視頻的naturalSize。您無法將videolayer.frame設置爲自定義CGRect。

    0
    var transform: CGAffineTransform 
    if isVideoAssetPortrait == true { 
        let scale = naturalSize.height/naturalSize.width 
        transform = CGAffineTransformMakeScale(scale, 1) 
        transform = CGAffineTransformConcat(videoTrack.preferredTransform, transform) 
    } else { 
        let scale = naturalSize.width/naturalSize.height 
        transform = CGAffineTransformMakeScale(1, scale) 
    } 
    videoLayerInstruction.setTransform(transform, atTime: kCMTimeZero) 
    

    我受到了這個https://www.snip2code.com/Snippet/42212/Crop-video-to-square-with-a-specified-si的啓發。
    但是,我實際上並不知道這是幹什麼的。我複製了代碼,但它不起作用。
    我看到視頻變形了,因此,我試圖讓它變形,它的工作原理。如果你仍然有任何問題。請聯繫我。這裏是我自己寫的樣本代碼: