AVAssetExportSession 音视频的剪辑,以及格式的装换

原创
2016/04/25 14:02
阅读数 1.1K

    //第一种方式

    

    //asset生成必须为文件的url,而且是本地

    AVAsset *mediaAsset = _player.currentItem.asset;

    

    //AVMutableComposition 可以进行音视频的组合

    

    AVAssetExportSession *es = [[AVAssetExportSession alloc] initWithAsset:mediaAsset presetName:AVAssetExportPresetPassthrough];

    

    NSString *outPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"out.mov"];

    

    NSFileManager *fileManager = [NSFileManager defaultManager];

    [fileManager removeItemAtPath:outPath error:NULL];


    //格式的转换

    es.outputFileType = AVFileTypeQuickTimeMovie;

    es.outputURL = [[NSURL alloc] initFileURLWithPath:outPath];

    es.shouldOptimizeForNetworkUse=NO;

    CMTime start = CMTimeMakeWithSeconds(1.0, 600);

    CMTime duration = CMTimeMakeWithSeconds(3.0, 600);

    CMTimeRange range = CMTimeRangeMake(start, duration);

    //音频的时间范围

    es.timeRange = range;

    

    

    NSLog(@"exporting to %@",outPath);

    //异步输出完成后调用

    [es exportAsynchronouslyWithCompletionHandler:^{

        NSString *status = @"" ;

        

        if( es.status == AVAssetExportSessionStatusCompleted ) status = @"AVAssetExportSessionStatusCompleted";

        else if( es.status == AVAssetExportSessionStatusFailed ) status = @"AVAssetExportSessionStatusFailed";

        

        

        NSLog(@"done exporting to %@ status %d = %@ (%@)",outPath,es.status, status,[es error]);

    }];

    

    

    //第二种方式读取本地到另外一个地方

    

    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

    NSString *audioPath = [documentPath stringByAppendingPathComponent:[NSString stringWithFormat:@"audio"]];

    

    NSURL *fileUrl = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/1141.mp3",audioPath]];

    

    

    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:fileUrl options:nil];

    NSError *error = nil;

    

    NSArray *array=[_player.currentItem.asset tracksWithMediaType:AVMediaTypeAudio];

    

    AVAssetTrack *track=[[_player.currentItem.asset tracksWithMediaType:AVMediaTypeAudio]firstObject];

    

    NSLog(@"%@",_player.currentItem.asset);

    

    assetReader=[[AVAssetReader alloc]initWithAsset:_player.currentItem.asset error:&error];

    NSDictionary *readerOutputSettings=@{(id)AVFormatIDKey:@(kAudioFormatLinearPCM)};

    

    //如果读取失败接下来的代码不会执行。

    

    AVAssetReaderTrackOutput *trackOutput=[[AVAssetReaderTrackOutput alloc]initWithTrack:track outputSettings:readerOutputSettings];

    [assetReader addOutput:trackOutput];

    //先判断readYES

    BOOL read= [assetReader startReading];

    

    

    NSString *userPath = [audioPath stringByAppendingPathComponent:[NSString stringWithFormat:@"/writer1.wav"]];

    NSURL *outputURL=[NSURL fileURLWithPath:userPath];

    

    assetWriter=[[AVAssetWriter alloc]initWithURL:outputURL fileType:AVFileTypeWAVE error:nil];

    AudioChannelLayout channelLayout;

    memset(&channelLayout, 0, sizeof(AudioChannelLayout));

    channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;

    

    //lin PCM需要设置PCM一些相关的属性

    NSDictionary *writerOutputSetting=@{(id)AVFormatIDKey:@(kAudioFormatLinearPCM),(id)AVSampleRateKey:[NSNumber numberWithFloat:44100.0],AVNumberOfChannelsKey:[NSNumber numberWithInt: 2],AVLinearPCMBitDepthKey:[NSNumber numberWithInt:16],

                                        AVLinearPCMIsNonInterleaved:[NSNumber numberWithBool:NO],

                                        AVLinearPCMIsFloatKey:[NSNumber numberWithBool:NO],

                                        AVLinearPCMIsBigEndianKey:[NSNumber numberWithBool:NO],AVChannelLayoutKey:[ NSData dataWithBytes:&channelLayout length: sizeof( AudioChannelLayout ) ]};

    

    AVAssetWriterInput *writerInput=[[AVAssetWriterInput alloc]initWithMediaType:AVMediaTypeAudio outputSettings:writerOutputSetting];

    [assetWriter addInput:writerInput];

    BOOL writer=[assetWriter startWriting];

    

    

    dispatch_queue_t dispatchQueue=dispatch_queue_create("com/tapharmonic.WriterQueue", NULL);

    

    [assetWriter startSessionAtSourceTime:kCMTimeZero];

    [writerInput requestMediaDataWhenReadyOnQueue:dispatchQueue usingBlock:^{

        

        bool complete=NO;

        while ([writerInput isReadyForMoreMediaData]&& !complete) {

            NSLog(@"%@",assetWriter.error);

            CMSampleBufferRef sampleBuffer=[trackOutput copyNextSampleBuffer];

            if(sampleBuffer){

                BOOL result=[writerInput appendSampleBuffer:sampleBuffer];

                CFRelease(sampleBuffer);

                complete=!result;

            }else{

                [writerInput markAsFinished];

                complete=YES;

            }

        }

        if(complete){

            [assetWriter finishWritingWithCompletionHandler:^{

                AVAssetWriterStatus status=assetWriter.status;

                NSLog(@"%@",assetWriter.error);

                if(status==AVAssetWriterStatusCompleted){

                    NSLog(@"AVAssetWriterStatusCompleted");

                }else{

                    NSLog(@"AVAssetWriterStatusFailed");

                }

            }];

        }

    }];


AVAssetExportSession你可以取消这个生成操作,通过给session发送 cancelExport 消息。

失败原因:
· 如果导出的文件存在,或者导出的url在沙盒之外,这个导出操作会失败。
· 来了一个电话
· 你的程序在后台运行并且其他的应用开始播放。
这种情况下,你应该通知用户export失败,并且重新export。

展开阅读全文
打赏
1
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
1
分享
返回顶部
顶部