2016-01-05 2 views
3

Мне нужно выполнить эту функцию: на видео есть оверлей GIF, в надежде собрать это видео и GIF для нового видео. Я использую следующий код, но результат только видео без GIF:Добавить водяной знак GIF на видео в iOS

- (void)mixVideoAsset:(AVAsset *)videoAsset { 

    LLog(@"Begining"); 

    NSDate * begin = [NSDate date]; 

    // 2 - Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances. 
    AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init]; 

    // 3 - Video track 
    AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo 
                     preferredTrackID:kCMPersistentTrackID_Invalid]; 
    [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) 
         ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] 
         atTime:kCMTimeZero error:nil]; 

    // - Audio 
    AVMutableCompositionTrack *audioCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; 
    AVAssetTrack *audioTrack = [[videoAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; 
    [audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioTrack.timeRange.duration) ofTrack:audioTrack atTime:kCMTimeZero error:nil]; 

    // 3.1 - Create AVMutableVideoCompositionInstruction 
    AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; 
    mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, videoAsset.duration); 

    // 3.2 - Create an AVMutableVideoCompositionLayerInstruction for the video track and fix the orientation. 
    AVMutableVideoCompositionLayerInstruction *videolayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack]; 
    AVAssetTrack *videoAssetTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 
    UIImageOrientation videoAssetOrientation_ = UIImageOrientationUp; 
    BOOL isVideoAssetPortrait_ = NO; 
    CGAffineTransform videoTransform = videoAssetTrack.preferredTransform; 
    if (videoTransform.a == 0 && videoTransform.b == 1.0 && videoTransform.c == -1.0 && videoTransform.d == 0) { 
     videoAssetOrientation_ = UIImageOrientationRight; 
     isVideoAssetPortrait_ = YES; 
    } 
    if (videoTransform.a == 0 && videoTransform.b == -1.0 && videoTransform.c == 1.0 && videoTransform.d == 0) { 
     videoAssetOrientation_ = UIImageOrientationLeft; 
     isVideoAssetPortrait_ = YES; 
    } 
    if (videoTransform.a == 1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == 1.0) { 
     videoAssetOrientation_ = UIImageOrientationUp; 
    } 
    if (videoTransform.a == -1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == -1.0) { 
     videoAssetOrientation_ = UIImageOrientationDown; 
    } 
    [videolayerInstruction setTransform:videoAssetTrack.preferredTransform atTime:kCMTimeZero]; 
    [videolayerInstruction setOpacity:0.0 atTime:videoAsset.duration]; 

    // 3.3 - Add instructions 
    mainInstruction.layerInstructions = [NSArray arrayWithObjects:videolayerInstruction,nil]; 

    AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition]; 

    CGSize naturalSize; 
    if(isVideoAssetPortrait_){ 
     naturalSize = CGSizeMake(videoAssetTrack.naturalSize.height, videoAssetTrack.naturalSize.width); 
    } else { 
     naturalSize = videoAssetTrack.naturalSize; 
    } 

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

    // Watermark Layers 
    [self applyVideoEffectsToComposition:mainCompositionInst size:naturalSize]; 

    // 4 - Get path 
// 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]; 
    NSURL * url = TempVideoURL(); 

    // 5 - Create exporter 
    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition 
                     presetName:AVAssetExportPresetHighestQuality]; 
    exporter.outputURL=url; 
    exporter.outputFileType = AVFileTypeMPEG4; 
    exporter.shouldOptimizeForNetworkUse = YES; 
    exporter.videoComposition = mainCompositionInst; 
    [exporter exportAsynchronouslyWithCompletionHandler:^{ 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      NSDate * endDate = [NSDate date]; 
      NSTimeInterval interval = [endDate timeIntervalSinceDate:begin]; 
      LLog(@"completed %f senconds",interval); 

      ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init]; 
      if ([assetsLibrary videoAtPathIsCompatibleWithSavedPhotosAlbum:exporter.outputURL]) { 
       [assetsLibrary writeVideoAtPathToSavedPhotosAlbum:exporter.outputURL completionBlock:NULL]; 
      } 
     }); 
    }]; 

} 

Добавить Gif Watermark

- (void)applyVideoEffectsToComposition:(AVMutableVideoComposition *)composition size:(CGSize)size 
{ 

    // - set up the parent layer 
    CALayer *parentLayer = [CALayer layer]; 
    CALayer *videoLayer = [CALayer layer]; 
    parentLayer.frame = CGRectMake(0, 0, size.width, size.height); 
    videoLayer.frame = CGRectMake(0, 0, size.width, size.height); 
    [parentLayer addSublayer:videoLayer]; 

    size.width = 100; 
    size.height = 100; 

    // - set up the overlay 
    CALayer *overlayLayer = [CALayer layer]; 
    overlayLayer.frame = CGRectMake(0, 100, size.width, size.height); 

    NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:@"jiafei" withExtension:@"gif"]; 
    [BBGifManager startGifAnimationWithURL:fileUrl inLayer:overlayLayer]; 

// UIImage * image = [UIImage imageNamed:@"gifImage.gif"]; 
// [overlayLayer setContents:(id)[image CGImage]]; 
// [overlayLayer setMasksToBounds:YES]; 

    [parentLayer addSublayer:overlayLayer]; 

    // - apply magic 
    composition.animationTool = [AVVideoCompositionCoreAnimationTool 
           videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer]; 

} 

Добавить CALayer анимаций

+ (void)startGifAnimationWithURL:(NSURL *)url inLayer:(CALayer *)layer { 
    CAKeyframeAnimation * animation = [self animationForGifWithURL:url]; 
    [layer addAnimation:animation forKey:@"contents"]; 
} 

Создать CAKeyFrameAnimation

+ (CAKeyframeAnimation *)animationForGifWithURL:(NSURL *)url { 

    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"]; 

    NSMutableArray * frames = [NSMutableArray new]; 
    NSMutableArray *delayTimes = [NSMutableArray new]; 

    CGFloat totalTime = 0.0; 
    CGFloat gifWidth; 
    CGFloat gifHeight; 

    CGImageSourceRef gifSource = CGImageSourceCreateWithURL((CFURLRef)url, NULL); 

    // get frame count 
    size_t frameCount = CGImageSourceGetCount(gifSource); 
    for (size_t i = 0; i < frameCount; ++i) { 
     // get each frame 
     CGImageRef frame = CGImageSourceCreateImageAtIndex(gifSource, i, NULL); 
     [frames addObject:(__bridge id)frame]; 
     CGImageRelease(frame); 

     // get gif info with each frame 
     NSDictionary *dict = (NSDictionary*)CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(gifSource, i, NULL)); 
     NSLog(@"kCGImagePropertyGIFDictionary %@", [dict valueForKey:(NSString*)kCGImagePropertyGIFDictionary]); 

     // get gif size 
     gifWidth = [[dict valueForKey:(NSString*)kCGImagePropertyPixelWidth] floatValue]; 
     gifHeight = [[dict valueForKey:(NSString*)kCGImagePropertyPixelHeight] floatValue]; 

     // kCGImagePropertyGIFDictionary中kCGImagePropertyGIFDelayTime,kCGImagePropertyGIFUnclampedDelayTime值是一样的 
     NSDictionary *gifDict = [dict valueForKey:(NSString*)kCGImagePropertyGIFDictionary]; 
     [delayTimes addObject:[gifDict valueForKey:(NSString*)kCGImagePropertyGIFDelayTime]]; 

     totalTime = totalTime + [[gifDict valueForKey:(NSString*)kCGImagePropertyGIFDelayTime] floatValue]; 

     CFRelease((__bridge CFTypeRef)(dict)); 
    } 

    if (gifSource) { 
     CFRelease(gifSource); 
    } 

    NSMutableArray *times = [NSMutableArray arrayWithCapacity:3]; 
    CGFloat currentTime = 0; 
    NSInteger count = delayTimes.count; 
    for (int i = 0; i < count; ++i) { 
     [times addObject:[NSNumber numberWithFloat:(currentTime/totalTime)]]; 
     currentTime += [[delayTimes objectAtIndex:i] floatValue]; 
    } 

    NSMutableArray *images = [NSMutableArray arrayWithCapacity:3]; 
    for (int i = 0; i < count; ++i) { 
     [images addObject:[frames objectAtIndex:i]]; 
    } 

    animation.keyTimes = times; 
    animation.values = images; 
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 
    animation.duration = totalTime; 
    animation.repeatCount = HUGE_VALF; 

    return animation; 
} 
+0

Я вижу, что ответ сработал для вас. Могли ли вы добавить gif с прозрачностью? Я бы хотел добавить снегопад gif, например, над видео и иметь все видео под gif. – user3344977

+0

@jasonwang дать мне библиотеку BBGifManager –

ответ

1

Вы должны настроить параметры animation CoreAnimation:

animation.beginTime = AVCoreAnimationBeginTimeAtZero; 
animation.removedOnCompletion = NO; 
+0

Работает. Спасибо! – Jasonwang

+0

Отлично. @Jasonwang, если ответ работает на вас, примите как правильный –

0

На всякий случай вот the example on swift3, как сделать то же самое - вставлять анимированные кадры/изображения в видео (не совсем GIF, но массив образов). Он использует AVAssetExportSession и AVMutableVideoComposition вместе с AVMutableVideoCompositionInstruction и CAKeyframeAnimation для анимации кадров.

 Смежные вопросы

  • Нет связанных вопросов^_^