Home / IOS Development / ios – Videos and images are not exported properly

ios – Videos and images are not exported properly



I’m trying to export a simple video collage with two videos and two photos side by side. However, I do get a few issues. When I try to export them all, the videos are not in the correct position and they appear to be covered by the images, but the images themselves are not displayed. The background color is also not displayed for some reason.

I used the same code below to export only the videos, and it worked fine, but the other images are added to all sorts of pauses.

I have tried to merge all the layers, I tried to add extra CALayers for the videos, I tried to put all the layers to content filling, but I have not had any luck.

- (void)exportVideo {
    /// Create the session composition
    AVMutableComposition *composition = [[AVMutableComposition alloc] init];

    /// Create the video instruction object
    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    
    /// Set the instruction to be a length of the first video
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, firstVideo.duration);

    /// Create a CALayer for the background
    CALayer *backgroundLayer = [CALayer layer];
    
    /// Wrap the background layer to match the vdieo
    backgroundLayer.frame = CGRectMake(0, 0, exportSize.width, exportSize.height);

    /// Set the background layer to be red
    backgroundLayer.backgroundColor = backgroundColor.CGColor;

    /// Create a CALayer for the videos to be embeded in
    /// The videoLayer must match the size of the video to allow the videos to be anywhere
    CALayer *videoLayer = [CALayer layer];
    videoLayer.frame = backgroundLayer.frame;

    /// Create a CALayer for the images to be embeded in
    /// The imageLayer must match the size of the video to allow the images to be anywhere
    CALayer *imageLayer = [CALayer layer];
    imageLayer.frame = backgroundLayer.frame;

    /// Add the two images to the imageLayer
    [self addImage:self.firstImage toLayer:imageLayer];
    [self addImage:self.secondImage toLayer:imageLayer];

    /// Create an array for the layer instructions to be written to
    NSMutableArray *layerInstructions = [NSMutableArray new];

    /// Add the videos to the above array
    [self addVideo:self.firstVideo toLayerInstructions:layerInstructions usingComposition:composition];
    [self addVideo:self.secondVideo toLayerInstructions:layerInstructions usingComposition:composition];

    /// Set the video instructions to the main instruction
    instruction.layerInstructions = layerInstructions;

    /// Create the final output layer
    /// Again, it's size needs to match the video
    CALayer *outputLayer = [CALayer layer];
    outputLayer.frame = videoLayer.frame;

    /// Add all children layers
    [outputLayer addSublayer:backgroundLayer];
    [outputLayer addSublayer:videoLayer];
    [outputLayer addSublayer:imageLayer];

    /// Create the final Video Composition object
    AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];

    /// Set the main video instruction
    videoComposition.instructions = [NSArray arrayWithObject:instruction];

    /// Set how long the frames are
    videoComposition.frameDuration = CMTimeMake(1
, 30); /// Set the size of the output video videoComposition.renderSize = CGSizeMake(exportSize.width, exportSize.height); /// Write the animation tool with the contained layers videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:outputLayer]; /// Generate the output URL NSURL *url = [AssetUtility outputPath:@"export.mov"]; /// Create the Export Session AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetHighestQuality]; exporter.outputURL = url; exporter.videoComposition = videoComposition; exporter.outputFileType = AVFileTypeQuickTimeMovie; /// Finally, export the video [exporter exportAsynchronouslyWithCompletionHandler:^{ NSLog(@"Done: %@", exporter.error); if (!exporter.error) UISaveVideoAtPathToSavedPhotosAlbum(url.path, nil, nil, nil); }]; } - (void)addImage:(UIImageView *)imageView toLayer:(CALayer *)layer { /// Create CALayer CALayer *image = [CALayer layer]; /// Position CALayer where UIImageView is image.frame = imageView.frame; /// Instruct CALayer to wrap to it's bounds image.masksToBounds = YES; /// Write the UIImage to the CALayer image.contents = CFBridgingRelease(imageView.image.CGImage); /// Display this CALayer within the imageLayer [imageLayer addSublayer:image]; } - (void)addVideo:(PHAsset *)asset toLayerInstructions:(NSMutableArray *)layerInstructions usingComposition:(AVMutableComposition *)composition { /// Uses custom utility class to get the AVAsset and XY coordinates from PHAsset AVAsset *video = [AssetUtility getVideo:asset]; NSArray *coordinates = [AssetUtility getCoordinates:asset]; /// AVMutableCompositionTrack *track = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; [track insertTimeRange:CMTimeRangeMake(kCMTimeZero, video.duration) ofTrack:[ objectAtIndex:0] atTime:kCMTimeZero error:nil]; /// AVMutableVideoCompositionLayerInstruction *instruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:track]; [instruction setTransform:CGAffineTransformMakeTranslation([coordinates objectAtIndex:0], [coordinates objectAtIndex:1]) atTime:kCMTimeZero]; /// Add this video's instructions to the other instructions [layerInstructions addObject:instruction]; }


Source link