【问题标题】:How to capture just the audio or video while streaming a video from a URL?如何在从 URL 流式传输视频时仅捕获音频或视频?
【发布时间】:2015-02-02 04:39:56
【问题描述】:

我想在我的 iOS 应用程序上从 Web 流式传输视频时只捕获音频和视频(不带音频)。

我用谷歌搜索过,但找不到类似的资源。

有可能吗?

任何指向一些相关资源的指针?

谢谢。

更新:
感谢您的回答林赛。该解决方案似乎有效。
我有另一个问题。如果我需要在播放(流式传输)视频时对视频的一部分执行此工作(例如当用户单击开始录制和停止录制时),您会怎么做?你觉得也可以吗?

【问题讨论】:

    标签: ios audio video video-streaming


    【解决方案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");
                 }
             }
         }];
    }
    

    【讨论】:

    • 感谢林赛的回答!我要试一试,然后再找你。
    • 感谢您的回答林赛。该解决方案似乎有效。我有另一个问题。如果我需要在播放(流式传输)视频时对视频的一部分执行此工作(例如当用户单击开始录制和停止录制时),你会怎么做?你觉得也可以吗?
    • @technophyle 您应该能够将 CMTimeRangeMake 的所有实例更改为您需要的任何范围
    猜你喜欢
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 2012-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-25
    • 2013-11-15
    相关资源
    最近更新 更多