Save video with modified playback speed using SCRecorder in Objective-C
Asked Answered
S

2

6

Using SCRecorder want to save video after recording, with different playback speed chosen by user ex: 2x, 3x. Using AVPlayer, it can be achieved using this code:

//create mutable composition
AVMutableComposition *mixComposition = [AVMutableComposition composition];

AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                               preferredTrackID:kCMPersistentTrackID_Invalid];
NSError *videoInsertError = nil;
BOOL videoInsertResult = [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
                                                        ofTrack:[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
                                                         atTime:kCMTimeZero
                                                          error:&videoInsertError];
if (!videoInsertResult || nil != videoInsertError) {
    //handle error
    return;
}

//slow down whole video by 2.0
double videoScaleFactor = 2.0;
CMTime videoDuration = asset.duration;

[compositionVideoTrack scaleTimeRange:CMTimeRangeMake(kCMTimeZero, videoDuration)
                           toDuration:CMTimeMake(videoDuration.value*videoScaleFactor, videoDuration.timescale)];

//export
AVAssetExportSession* assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition
                                                                  //   presetName:AVAssetExportPresetLowQuality];

But, not getting how to achieve the same using SCRecorder library. Please guide. Thanks in advance.

Salient answered 7/12, 2018 at 6:15 Comment(0)
S
6

Finally got answer my self:

- (void)SlowMotion:(NSURL *)URl
{
AVURLAsset* videoAsset = [AVURLAsset URLAssetWithURL:URl options:nil];    //self.inputAsset;

AVAsset *currentAsset = [AVAsset assetWithURL:URl];
AVAssetTrack *vdoTrack = [[currentAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
//create mutable composition
AVMutableComposition *mixComposition = [AVMutableComposition composition];

AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

NSError *videoInsertError = nil;
BOOL videoInsertResult = [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
                                                    ofTrack:[[videoAsset     tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
                                                     atTime:kCMTimeZero
                                                      error:&videoInsertError];
if (!videoInsertResult || nil != videoInsertError) {
//handle error
return;
}

NSError *audioInsertError =nil;
BOOL audioInsertResult =[compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
                                                   ofTrack:[[currentAsset    tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]
                                                    atTime:kCMTimeZero
                                                     error:&audioInsertError];

if (!audioInsertResult || nil != audioInsertError) {
//handle error
return;
}

CMTime duration =kCMTimeZero;
duration=CMTimeAdd(duration, currentAsset.duration);
//slow down whole video by 2.0
double videoScaleFactor = 2.0;
CMTime videoDuration = videoAsset.duration;

[compositionVideoTrack scaleTimeRange:CMTimeRangeMake(kCMTimeZero, videoDuration)
                       toDuration:CMTimeMake(videoDuration.value*videoScaleFactor, videoDuration.timescale)];
[compositionAudioTrack scaleTimeRange:CMTimeRangeMake(kCMTimeZero, videoDuration)
                       toDuration:CMTimeMake(videoDuration.value*videoScaleFactor, videoDuration.timescale)];
[compositionVideoTrack setPreferredTransform:vdoTrack.preferredTransform];

    NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docsDir = [dirPaths objectAtIndex:0];
    NSString *outputFilePath = [docsDir stringByAppendingPathComponent:[NSString stringWithFormat:@"slowMotion.mov"]];
    if ([[NSFileManager defaultManager] fileExistsAtPath:outputFilePath])
    [[NSFileManager defaultManager] removeItemAtPath:outputFilePath error:nil];
    NSURL *_filePath = [NSURL fileURLWithPath:outputFilePath];

//export
AVAssetExportSession* assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition
                                                                    presetName:AVAssetExportPresetLowQuality];
assetExport.outputURL=_filePath;
                      assetExport.outputFileType =                AVFileTypeQuickTimeMovie;
exporter.shouldOptimizeForNetworkUse = YES;
                       [assetExport exportAsynchronouslyWithCompletionHandler:^
                        {

                            switch ([assetExport status]) {
                                case AVAssetExportSessionStatusFailed:
                                {
                                    NSLog(@"Export session faiied with error: %@", [assetExport error]);
                                    dispatch_async(dispatch_get_main_queue(), ^{
                                        // completion(nil);
                                    });
                                }
                                    break;
                                case AVAssetExportSessionStatusCompleted:
                                {

                                    NSLog(@"Successful");
                                    NSURL *outputURL = assetExport.outputURL;

                                    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
                                    if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:outputURL]) {

                                        [self writeExportedVideoToAssetsLibrary:outputURL];
                                    }
                                    dispatch_async(dispatch_get_main_queue(), ^{
                                        //                                            completion(_filePath);
                                    });

                                }
                                    break;
                                default:

                                    break;
                            }


                        }];


 }

 - (void)writeExportedVideoToAssetsLibrary :(NSURL *)url {
NSURL *exportURL = url;
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:exportURL]) {
[library writeVideoAtPathToSavedPhotosAlbum:exportURL completionBlock:^(NSURL *assetURL, NSError *error){
    dispatch_async(dispatch_get_main_queue(), ^{
        if (error) {
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[error localizedDescription]
                                                                message:[error localizedRecoverySuggestion]
                                                               delegate:nil
                                                      cancelButtonTitle:@"OK"
                                                      otherButtonTitles:nil];
            [alertView show];
        }
        if(!error)
        {
           // [activityView setHidden:YES];
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Sucess"
                                                                message:@"video added to gallery successfully"
                                                               delegate:nil
                                                      cancelButtonTitle:@"OK"
                                                      otherButtonTitles:nil];
            [alertView show];
        }
 #if !TARGET_IPHONE_SIMULATOR
        [[NSFileManager defaultManager] removeItemAtURL:exportURL error:nil];
 #endif
    });
}];
} else {
NSLog(@"Video could not be exported to assets library.");
}

}
Salient answered 14/12, 2018 at 5:38 Comment(0)
T
0

SCVideoConfiguration having one property timeScale.

You cant try SCAssetExportSession. which takes SCVideoConfiguration as input.

You can also use SCAssetExportSession, which is the SCRecorder counterpart of AVAssetExportSession.(SCRecorder docs)

 /* The time scale of the video
 A value more than 1 will make the buffers last longer, it creates
 a slow motion effect. A value less than 1 will make the buffers be
 shorter, it creates a timelapse effect.

 Only used in SCRecorder.
 */
@property (assign, nonatomic) CGFloat timeScale;
Thermobarograph answered 11/12, 2018 at 10:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.