Как да заснемете само аудио или видео, докато поточно предавате видео от URL?

Бих искал да заснема само аудио и само видео (без аудио), докато стриймвам видео от мрежата в моето приложение за iOS.

Търсих го в Google, но не можах да намеря подобен ресурс.

Възможно ли е изобщо?

Някакви насоки към някои свързани ресурси?

Благодаря.

Актуализация:
Благодаря за отговора Линдзи. Решението изглежда работи.
Имам още един въпрос. Ако трябва да изпълня тази работа с част от видеоклипа (като например, когато потребителят щракне върху Старт на записа и Спрете записа), докато възпроизвеждам (поточно) видеото, как бихте направили това? Мислите ли, че също е възможно?


person technophyle    schedule 31.01.2015    source източник


Отговори (1)


Доста интересен въпрос. Ето какво измислих:

Доколкото знам, не можете директно да запазите видеопотока, който се възпроизвежда от вашия MPMoviePlayerController, но можете да запазите данните, тъй като видеоклипът ви се предава, като използвате dataWithContentsOfURL:. След това, след като данните бъдат запазени успешно, можете да ги разделите на видео и/или аудио компоненти, напр.

- (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");
             }
         }
     }];
}
person Lyndsey Scott    schedule 01.02.2015
comment
Благодаря за отговора Линдзи! Ще го пробвам и ще се върна при вас. - person technophyle; 01.02.2015
comment
Благодаря за отговора Линдзи. Решението изглежда работи. Имам още един въпрос. Ако трябва да изпълня тази работа с част от видеоклипа (като например, когато потребителят щракне върху Старт на записа и Спрете записа), докато възпроизвеждам (поточно) видеото, как бихте направили това? Мислите ли, че също е възможно? - person technophyle; 01.02.2015
comment
@technophyle Трябва да можете да промените всички екземпляри на CMTimeRangeMake до какъвто и да е диапазон, от който се нуждаете - person Lyndsey Scott; 02.02.2015