如何在从 URL 流式传输视频时仅捕获音频或视频?
How to capture just the audio or video while streaming a video from a URL?
我想在 iOS 应用程序上从 Web 流式传输视频时仅捕获音频和视频(无音频)。
我用谷歌搜索了它,但找不到类似的资源。
有可能吗?
是否有一些相关资源的指针?
谢谢。
更新:
谢谢林赛的回答。该解决方案似乎有效。
我有另一个问题。如果我需要在播放(流式传输)视频时对视频的一部分执行此操作(例如当用户单击“开始录制”和“停止录制”时),您会怎么做?你觉得也可以吗?
非常有趣的问题。这是我想出的:
据我所知,您无法直接保存从您的 MPMoviePlayerController
播放的视频流,但您可以将数据 保存为 您的视频正在播放通过使用 dataWithContentsOfURL:
。然后一旦数据保存成功,你就可以把它拆分成视频and/or音频组件,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");
}
}
}];
}
我想在 iOS 应用程序上从 Web 流式传输视频时仅捕获音频和视频(无音频)。
我用谷歌搜索了它,但找不到类似的资源。
有可能吗?
是否有一些相关资源的指针?
谢谢。
更新:
谢谢林赛的回答。该解决方案似乎有效。
我有另一个问题。如果我需要在播放(流式传输)视频时对视频的一部分执行此操作(例如当用户单击“开始录制”和“停止录制”时),您会怎么做?你觉得也可以吗?
非常有趣的问题。这是我想出的:
据我所知,您无法直接保存从您的 MPMoviePlayerController
播放的视频流,但您可以将数据 保存为 您的视频正在播放通过使用 dataWithContentsOfURL:
。然后一旦数据保存成功,你就可以把它拆分成视频and/or音频组件,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");
}
}
}];
}