technophyle
technophyle

Reputation: 9128

How to capture just the audio or video while streaming a video from a URL?

I would like to capture just audio and just video (without audio) while streaming a video from Web on my iOS application.

I have googled it but could not find one similar resource.

Is it possible at all?

Any pointers to some related resources?

Thanks.

Update:
Thanks for your answer Lyndsey. The solution seems to work.
I have another question. If I need to do this job to a portion of the video (like when the user clicks on Start Recording and Stop Recording) while playing (streaming) the video, how would you do that? Do you think it is also possible?

Upvotes: 0

Views: 276

Answers (1)

Lyndsey Scott
Lyndsey Scott

Reputation: 37290

Pretty interesting question. Here's what I came up with:

As far as I know, you can't directly save the video stream playing from your MPMoviePlayerController, but you can save the data as your video is streaming by using dataWithContentsOfURL:. Then once the data is saved successfully, you can split it into video and/or audio components, ex:

- (void)saveFullVideo {

    // Create a temporary file path to hold the
    // complete version of the video
    NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
    NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:@"temp"]
       URLByAppendingPathExtension:@"mov"]; // <-- assuming the streaming video's a .mov file

    NSError *error = nil;
    NSData *urlData = [NSData dataWithContentsOfURL:streamingURL];
    [urlData writeToURL:fileURL options:NSAtomicWrite error:&error];

    // If the data is written to the temporary file path
    // successfully, split it into video and audio components
    if (!error) {
        [self saveVideoComponent:fileURL];
        [self saveAudioComponent:fileURL];
    }
}

- (void)saveVideoComponent:(NSURL*)videoUrl {

    AVURLAsset* videoAsset  = [[AVURLAsset alloc]initWithURL:videoUrl options:nil];

    AVMutableComposition *composition = [AVMutableComposition composition];

    // Create a mutable track of type video
    AVMutableCompositionTrack *videoCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

    NSError *error = nil;

    // Get the video portion of the track and insert it
    // into the mutable video composition track
    AVAssetTrack *video = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
    [videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:video atTime:kCMTimeZero error:&error];

    // Create a session to export this composition
    AVAssetExportSession* assetExport = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetPassthrough];

    // Create the path to which you'll export the video
    NSString *docPath = [NSSearchPathForDirectoriesInDomains
                         (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *exportPath = [docPath stringByAppendingPathComponent:@"/video_path.mp4"];
    NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];

    // Remove the old file at the export path if one exists
    if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath])
    {
        [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
    }

    assetExport.outputFileType = AVFileTypeMPEG4;

    assetExport.outputURL = exportUrl;
    assetExport.shouldOptimizeForNetworkUse = YES;

    [assetExport exportAsynchronouslyWithCompletionHandler:
     ^(void )
     {
         switch (assetExport.status)
         {
             case AVAssetExportSessionStatusCompleted: {
                 NSLog(@"Video export Saved to path: %@", exportUrl);
                 break;
             } case AVAssetExportSessionStatusFailed: {
                 NSLog(@"Export Failed");
                 NSLog(@"ExportSessionError: %@", [assetExport.error localizedDescription]);
                 break;
             } case AVAssetExportSessionStatusCancelled: {
                 NSLog(@"Export Cancelled");
                 NSLog(@"ExportSessionError: %@", [assetExport.error localizedDescription]);
                 break;
             } default: {
                 NSLog(@"Export Default condition");
             }    
         }
     }];
}

- (void)saveAudioComponent:(NSURL*)videoUrl {

    AVURLAsset* videoAsset  = [[AVURLAsset alloc]initWithURL:videoUrl options:nil];

    AVMutableComposition *composition = [AVMutableComposition composition];

    // Create a mutable track of type audio
    AVMutableCompositionTrack *audioCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

    NSError *error = nil;

    // Get the audio portion of the track and insert it
    // into the mutable audio composition track
    AVAssetTrack *audio = [[videoAsset tracksWithMediaType:AVMediaTypeAudio] firstObject];
    [audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:audio atTime:kCMTimeZero error:&error];


    // Create a session to export this composition
    AVAssetExportSession* assetExport = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetPassthrough];

    // Create the path to which you'll export the audio
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"VideoFolder"];
    // Create folder if needed
    [[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:YES attributes:nil error:nil];

    NSString *exportPath = [dataPath stringByAppendingPathComponent:@"audio_path.caf"];
    NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];

    // Remove the old file at the export path if one exists
    if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath])
    {
        [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
    }

    assetExport.outputFileType = AVFileTypeCoreAudioFormat;

    assetExport.outputURL = exportUrl;
    assetExport.shouldOptimizeForNetworkUse = YES;

    [assetExport exportAsynchronouslyWithCompletionHandler:
     ^(void )
     {
         switch (assetExport.status)
         {
             case AVAssetExportSessionStatusCompleted: {
                 NSLog(@"Audio export Saved to path: %@", exportUrl);
                 //[self playAudio:exportUrl];
                 break;
             } case AVAssetExportSessionStatusFailed: {
                 NSLog(@"Export Failed");
                 NSLog(@"ExportSessionError: %@", [assetExport.error localizedDescription]);
                 break;
             } case AVAssetExportSessionStatusCancelled: {
                 NSLog(@"Export Cancelled");
                 NSLog(@"ExportSessionError: %@", [assetExport.error localizedDescription]);
                 break;
             } default: {
                 NSLog(@"Export Default condition");
             }
         }
     }];
}

Upvotes: 1

Related Questions