动态判断合成视频,保留原音,混音音乐,设置音量大小

来源:互联网 发布:淘宝行业关键词 编辑:程序博客网 时间:2024/06/05 03:55

项目里有一个需求,就是动态判断图片合成的mov与自己自拍的视频合成,然后还要保留自拍的原音,最后再混音一个音乐,并设置音量大小下面是代码,可以模拟器测试,但测试的时候最后不要开断点

加入framework



////  ViewController.h//  img+mov+audio+video////  Created by 王颜龙 on 14-1-14.//  Copyright (c) 2014年 longyan. All rights reserved.//#import <UIKit/UIKit.h>#import "CompositionCenter.h"@interface ViewController : UIViewController<CompositionDelegate>- (IBAction)start:(UIButton *)sender;- (IBAction)soundMixing:(UIButton *)sender;- (IBAction)overMix:(id)sender;@end

#import "CompositionCenter.h"#import "ViewController.h"#import "MovItem.h"@interface ViewController ()@property(nonatomic,strong)NSMutableArray *dataArr;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];    NSString *fileStr = [[NSBundle mainBundle]pathForResource:@"IMG_0598" ofType:@"MOV"];    NSURL *fileUrl = [NSURL fileURLWithPath:fileStr];        NSString *fileStr2 = [[NSBundle mainBundle]pathForResource:@"IMG_0634" ofType:@"MOV"];    NSURL *fileUrl2 = [NSURL fileURLWithPath:fileStr2];        self.dataArr = [[NSMutableArray alloc]initWithCapacity:0];        for (int i = 0; i < 30; i++) {        MovItem *item = [[MovItem alloc]init];        item.type = @"img";        item.image = [UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg",arc4random()%10+1]];        [self.dataArr addObject:item];    }    MovItem *item = [[MovItem alloc]init];    item.type = @"mov";    item.fileUrl = fileUrl;    [self.dataArr addObject:item];        for (int i = 0; i < 30; i++) {        MovItem *item = [[MovItem alloc]init];        item.type = @"img";        item.image = [UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg",arc4random()%10+1]];        [self.dataArr addObject:item];    }        MovItem *item2 = [[MovItem alloc]init];    item2.type = @"mov";    item2.fileUrl = fileUrl2;    [self.dataArr addObject:item2];        for (int i = 0; i < 30; i++) {        MovItem *item = [[MovItem alloc]init];        item.type = @"img";        item.image = [UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg",arc4random()%10+1]];        [self.dataArr addObject:item];    }    }- (void)didReceiveMemoryWarning{    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}- (IBAction)start:(UIButton *)sender {        [[CompositionCenter sharedDataCenter]startComposition:self.dataArr];    [[CompositionCenter sharedDataCenter] setDeleagte:self];    }- (IBAction)soundMixing:(UIButton *)sender {        //不能开断点测试    [[CompositionCenter sharedDataCenter] soundMixing];    }- (IBAction)overMix:(id)sender {        //最后的混音    [[CompositionCenter sharedDataCenter]overMix];}- (void)CompositionDidBegin{    NSLog(@"begin");}- (void)CompositionDidFinish:(NSURL *)url{    NSLog(@"Finish");}- (void)CompositionDidFail{    NSLog(@"Fail");}@end

////  DataCenter.h//  img+mov+audio+video////  Created by 王颜龙 on 14-1-14.//  Copyright (c) 2014年 longyan. All rights reserved.//#import <Foundation/Foundation.h>@protocol CompositionDelegate <NSObject>- (void)CompositionDidBegin;- (void)CompositionDidFinish:(NSURL *)url;- (void)CompositionDidFail;@end@interface CompositionCenter : NSObject{    CGRect imageRect;    dispatch_queue_t _serialQueue;    NSMutableArray *audioMixParams;}@property(nonatomic,strong)NSMutableArray *trackArr;@property(nonatomic, strong)NSString*                               videoPath;@property (nonatomic,strong)NSURL *url;@property(nonatomic, strong)AVAssetWriter*                          videoWriter;@property(nonatomic, strong)AVAssetWriterInput*                     writerInput;@property(nonatomic, strong)AVAssetWriterInputPixelBufferAdaptor*   adaptor;@property(nonatomic, assign)BOOL                                    firstImgAdded;@property(nonatomic,unsafe_unretained)id<CompositionDelegate>   deleagte;@property(nonatomic,assign)CMTime allTime;@property(nonatomic,strong)NSMutableArray *tmpArr;@property(nonatomic,strong)NSMutableArray *tmpDetailArr;@property(nonatomic,strong)NSURL *overUrl;@property(nonatomic,strong)NSURL *mixURL;+ (CompositionCenter*) sharedDataCenter;- (void)startComposition:(NSMutableArray *)arr;- (void)soundMixing;- (void)overMix;@end

////  DataCenter.m//  img+mov+audio+video////  Created by 王颜龙 on 14-1-14.//  Copyright (c) 2014年 longyan. All rights reserved.//#import "ExtAudioFileMixer.h"#import "MovItem.h"#import "CompositionCenter.h"#import "MovDetailItem.h"static CompositionCenter *sharedObj = nil; //第一步:静态实例,并初始化。@implementation CompositionCenter+ (CompositionCenter*) sharedDataCenter  //第二步:实例构造检查静态实例是否为nil{    @synchronized (self)    {        if (sharedObj == nil) {            //如果为nil,创建实例            sharedObj = [[[self class] alloc]init];        }    }    return sharedObj;}#pragma mark - 下面这些方法,是为了确保只有一个实例对象+(id)allocWithZone:(NSZone *)zone{    if (sharedObj == nil) {        sharedObj = [super allocWithZone:zone];    }    return sharedObj;}//实现copy协议,返回本身- (id)copyWithZone:(NSZone *)zone{    return sharedObj;}#pragma mark - 动态保存movstatic int numCount = 0;- (void)startComposition:(NSMutableArray *)arr{        NSLog(@"保存路径===%@",[self getLibarayPath]);        if (self.deleagte && [self.deleagte respondsToSelector:@selector(CompositionDidBegin)]) {        [self.deleagte CompositionDidBegin];    }        self.allTime = kCMTimeZero;    //存放png的数组    self.tmpArr = [[NSMutableArray alloc]initWithCapacity:0];    //存放合成mov的item数组    self.tmpDetailArr = [[NSMutableArray alloc]initWithCapacity:0];    //存放track的数组    self.trackArr = [[NSMutableArray alloc]initWithCapacity:0];        //创建串行队列    _serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);        __block int num = 0;        //使用串行队列控制合成顺序    for (MovItem *item in arr) {        dispatch_async(_serialQueue, ^{                        if ([item.type isEqualToString:@"img"]) {                                [self.tmpArr addObject:item];                                NSLog(@"jiarushuzu %d",num);                                if (num+1 == arr.count) {                    NSLog(@"over  %d",num);                    [self initRecord];                    [self startCamera];                    [self.tmpArr removeAllObjects];                }                            }else{                                NSLog(@"mov save %d",num);                                [self initRecord];                [self startCamera];                                [self saveMOV:item];                [self.tmpArr removeAllObjects];                            }            num++;                    });    }        numCount = 0;        //合成方法    [self Composition];}- (void)Composition{        dispatch_async(_serialQueue, ^{                //整合        AVMutableComposition* mixComposition = [[AVMutableComposition alloc] init];                AVMutableVideoCompositionInstruction * MainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];                CMTime tmpTime;                for (MovDetailItem *item in self.tmpDetailArr) {            NSLog(@"item === %d",item.num);                        //动态创建track            AVMutableCompositionTrack *firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];                                    if ( item.num == 1 ) {                tmpTime = kCMTimeZero;            }                        NSLog(@"tmpTime === %f",CMTimeGetSeconds(tmpTime));                        [firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, item.asset.duration) ofTrack:[[item.asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:tmpTime error:nil];                        //AUDIO TRACK            //如果是mov进行合成保留原声            if([item.type isEqualToString:@"mov"]){                                AVMutableCompositionTrack *AudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];                                [AudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, item.asset.duration) ofTrack:[[item.asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:tmpTime error:nil];                            }                        //FIXING ORIENTATION//            //调整视频方向            AVMutableVideoCompositionLayerInstruction *FirstlayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:firstTrack];                        AVAssetTrack *FirstAssetTrack = [[item.asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];                        UIImageOrientation FirstAssetOrientation_ = UIImageOrientationUp;                        BOOL  isFirstAssetPortrait_ = NO;                        CGAffineTransform firstTransform = FirstAssetTrack.preferredTransform;                        if(firstTransform.a == 0 && firstTransform.b == 1.0 && firstTransform.c == -1.0 && firstTransform.d == 0)  {FirstAssetOrientation_= UIImageOrientationRight; isFirstAssetPortrait_ = YES;}            if(firstTransform.a == 0 && firstTransform.b == -1.0 && firstTransform.c == 1.0 && firstTransform.d == 0)  {FirstAssetOrientation_ =  UIImageOrientationLeft; isFirstAssetPortrait_ = YES;}            if(firstTransform.a == 1.0 && firstTransform.b == 0 && firstTransform.c == 0 && firstTransform.d == 1.0)   {FirstAssetOrientation_ =  UIImageOrientationUp;}            if(firstTransform.a == -1.0 && firstTransform.b == 0 && firstTransform.c == 0 && firstTransform.d == -1.0) {FirstAssetOrientation_ = UIImageOrientationDown;}                        CGFloat FirstAssetScaleToFitRatio = 320/FirstAssetTrack.naturalSize.width;                        if(isFirstAssetPortrait_){                FirstAssetScaleToFitRatio = 320/FirstAssetTrack.naturalSize.height;                CGAffineTransform FirstAssetScaleFactor = CGAffineTransformMakeScale(FirstAssetScaleToFitRatio,FirstAssetScaleToFitRatio);                [FirstlayerInstruction setTransform:CGAffineTransformConcat(FirstAssetTrack.preferredTransform, FirstAssetScaleFactor) atTime:tmpTime];            }else{                CGAffineTransform FirstAssetScaleFactor = CGAffineTransformMakeScale(FirstAssetScaleToFitRatio,FirstAssetScaleToFitRatio);                [FirstlayerInstruction setTransform:CGAffineTransformConcat(CGAffineTransformConcat(FirstAssetTrack.preferredTransform, FirstAssetScaleFactor),CGAffineTransformMakeTranslation(0, 150)) atTime:tmpTime];            }                        tmpTime = [self addAllAVAssetDuration:item];            [FirstlayerInstruction setOpacity:0.0 atTime:self.allTime];            [self.trackArr insertObject:FirstlayerInstruction atIndex:0];                    }                MainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero,self.allTime);        MainInstruction.layerInstructions = self.trackArr;                AVMutableVideoComposition *MainCompositionInst = [AVMutableVideoComposition videoComposition];        MainCompositionInst.instructions = [NSArray arrayWithObject:MainInstruction];        MainCompositionInst.frameDuration = CMTimeMake(1, 30);                if (iPhone5) {            MainCompositionInst.renderSize = CGSizeMake(320.0, 568.0);        }else{            MainCompositionInst.renderSize = CGSizeMake(320.0, 480.0);//解决图像问题        }                NSString* fileName = [NSString stringWithFormat:@"%@.mov", @"over"];        NSString *filePath = [NSString stringWithFormat:@"%@/%@", [self getLibarayPath], fileName];        NSLog(@"输出路径 === %@",filePath);        NSURL *url = [NSURL fileURLWithPath:filePath];                //输出        AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];        exporter.outputURL=url;        exporter.outputFileType = AVFileTypeQuickTimeMovie;        exporter.videoComposition = MainCompositionInst;        exporter.shouldOptimizeForNetworkUse = YES;        [exporter exportAsynchronouslyWithCompletionHandler:^         {             dispatch_async(dispatch_get_main_queue(), ^{                 [self exportDidFinish:exporter];             });         }];            });}- (void)exportDidFinish:(AVAssetExportSession*)session{        if(session.status == AVAssetExportSessionStatusCompleted){                NSLog(@"!!!");        self.overUrl = session.outputURL;                if (self.deleagte && [self.deleagte respondsToSelector:@selector(CompositionDidFinish:)]) {            [self.deleagte CompositionDidFinish:self.overUrl];        }            }else if (session.status == AVAssetExportSessionStatusFailed){        if (self.deleagte && [self.deleagte respondsToSelector:@selector(CompositionDidFail)]) {            [self.deleagte CompositionDidFail];        }    }}#pragma mark - 视频保存本地- (void)saveMOV:(MovItem *)item{    numCount ++;    NSString* fileName = [NSString stringWithFormat:@"%d.mov", numCount];    NSString *filePath = [NSString stringWithFormat:@"%@/%@", [self getLibarayPath], fileName];        NSData *data = [NSData dataWithContentsOfURL:item.fileUrl];    [data writeToFile:filePath atomically:YES];        //创建合成mov的item    MovDetailItem *item0 = [[MovDetailItem alloc]init];    AVAsset *asset = [AVAsset assetWithURL:item.fileUrl];    item0.asset = asset;    item0.num = numCount;    item0.type = @"mov";    [self.tmpDetailArr addObject:item0];}#pragma mark - 初始化写入- (void)initRecord{    numCount ++;    //是否是第一次添加图片    self.firstImgAdded = FALSE;        //video路径    NSString* fileName = [NSString stringWithFormat:@"%d.mov", numCount];    self.videoPath = [NSString stringWithFormat:@"%@/%@", [self getLibarayPath], fileName];//    NSLog(@"输出== %@",self.videoPath);        //设置图片            CGSize frameSize = imageRect.size;        NSError* error = nil;        //创建写入对象    self.videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:self.videoPath] fileType:AVFileTypeQuickTimeMovie error:&error];        //如果出错,打印错误内容    if(error)    {        NSLog(@"error creating AssetWriter: %@",[error description]);        self.videoWriter = nil;        return;    }        //设置参数    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:                                   AVVideoCodecH264, AVVideoCodecKey,                                   [NSNumber numberWithInt:frameSize.width], AVVideoWidthKey,                                   [NSNumber numberWithInt:frameSize.height], AVVideoHeightKey,                                   nil];        //输入对象    self.writerInput = [AVAssetWriterInput                        assetWriterInputWithMediaType:AVMediaTypeVideo                        outputSettings:videoSettings];        //属性设置    NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];    [attributes setObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey];    [attributes setObject:[NSNumber numberWithUnsignedInt:frameSize.width] forKey:(NSString*)kCVPixelBufferWidthKey];    [attributes setObject:[NSNumber numberWithUnsignedInt:frameSize.height] forKey:(NSString*)kCVPixelBufferHeightKey];        //通过属性和writerInput 创建一个新的Adaptor    self.adaptor = [AVAssetWriterInputPixelBufferAdaptor                    assetWriterInputPixelBufferAdaptorWithAssetWriterInput:self.writerInput                    sourcePixelBufferAttributes:attributes];        //添加输入,必须在开始写入之前    [self.videoWriter addInput:self.writerInput];        self.writerInput.expectsMediaDataInRealTime = YES;        //开始写入    [self.videoWriter startWriting];    [self.videoWriter startSessionAtSourceTime:kCMTimeZero];}#pragma mark - 开始写入- (void)startCamera{    int count = 0;    while (self.tmpArr.count - count) {        MovItem *item = [self.tmpArr objectAtIndex:count];        UIImage *image = item.image;        CGImageRef image1 = image.CGImage;        [self writeImage:image1 withIndex:count];        count ++;    }        [self.writerInput markAsFinished];    [self.videoWriter finishWriting];        MovDetailItem *item = [[MovDetailItem alloc]init];    AVAsset *asset = [AVAsset assetWithURL:[NSURL fileURLWithPath:self.videoPath]];    item.asset = asset;    item.num = numCount;    item.type = @"img";    [self.tmpDetailArr addObject:item];}- (void)writeImage:(CGImageRef)img withIndex:(NSInteger)curCount{    CVPixelBufferRef buffer = NULL;    if (self.videoWriter == nil)    {        NSLog(@"error~~~~~~~~~~~");    }    if (self.firstImgAdded == FALSE)    {        buffer = [self pixelBufferFromCGImage:img];        BOOL result = [self.adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];        if (result == NO) //failes on 3GS, but works on iphone 4        {            NSLog(@"failed to append buffer");        }        if(buffer)        {            CVBufferRelease(buffer);        }        self.firstImgAdded = TRUE;    }    else    {        if (self.adaptor.assetWriterInput.readyForMoreMediaData)        {            CMTime frameTime = CMTimeMake(1, FramePerSec);            CMTime lastTime = CMTimeMake(curCount, FramePerSec);            CMTime presentTime = CMTimeAdd(lastTime, frameTime);                        buffer = [self pixelBufferFromCGImage:img];            BOOL result = [self.adaptor appendPixelBuffer:buffer withPresentationTime:presentTime];                        if (result == NO) //failes on 3GS, but works on iphone 4            {                NSLog(@"failed to append buffer");                NSLog(@"The error is %@", [self.videoWriter error]);            }            else            {                NSLog(@"write ok");            }            if(buffer)            {                CVBufferRelease(buffer);            }        }        else        {            NSLog(@"error");        }    }    }- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image{    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:                             [NSNumber numberWithBool:TRUE], kCVPixelBufferCGImageCompatibilityKey,                             [NSNumber numberWithBool:TRUE],kCVPixelBufferCGBitmapContextCompatibilityKey,                             nil];//是否兼容    CVPixelBufferRef pxbuffer = NULL;    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, imageRect.size.width,                                          imageRect.size.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options,                                          &pxbuffer);//返回kCVReturnSuccess kCFAllocatorDefault = nil    status=status;    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);//判断类型        CVPixelBufferLockBaseAddress(pxbuffer, 0);//访问地址    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);    NSParameterAssert(pxdata != NULL);        CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();    CGContextRef context = CGBitmapContextCreate(pxdata, imageRect.size.width,                                                 imageRect.size.height, 8, 4*imageRect.size.width, rgbColorSpace,                                                 kCGImageAlphaNoneSkipFirst);    NSParameterAssert(context);        CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));        CGContextDrawImage(context, CGRectMake(0, 0, imageRect.size.width, imageRect.size.height), image);    CGColorSpaceRelease(rgbColorSpace);    CGContextRelease(context);        CVPixelBufferUnlockBaseAddress(pxbuffer, 0);        return pxbuffer;}#pragma mark - 混音 取出mov的音频和选择的音乐混音- (void)soundMixing{    if (self.deleagte && [self.deleagte respondsToSelector:@selector(CompositionDidBegin)]) {        [self.deleagte CompositionDidBegin];    }        AVMutableComposition *composition = [AVMutableComposition composition];    audioMixParams = [[NSMutableArray alloc] initWithObjects:nil];        AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:self.overUrl options:nil];    CMTime startTime = CMTimeMakeWithSeconds(0, 1);    CMTime trackDuration = songAsset.duration;        [self setUpAndAddAudioAtPath:self.overUrl toComposition:composition start:startTime dura:trackDuration offset:CMTimeMake(14*44100, 44100)];        NSString * path = [[NSBundle mainBundle] pathForResource:@"最炫民族风" ofType:@"mp3"];    NSURL *assetURL2 = [NSURL fileURLWithPath:path];    [self setUpAndAddAudioAtPath:assetURL2 toComposition:composition start:startTime dura:trackDuration offset:CMTimeMake(0, 44100)];        AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];    audioMix.inputParameters = [NSArray arrayWithArray:audioMixParams];        //If you need to query what formats you can export to, here's a way to find out    NSLog (@"compatible presets for songAsset: %@",           [AVAssetExportSession exportPresetsCompatibleWithAsset:composition]);        AVAssetExportSession *exporter = [[AVAssetExportSession alloc]                                      initWithAsset: composition                                      presetName: AVAssetExportPresetAppleM4A];    exporter.audioMix = audioMix;    exporter.outputFileType = @"com.apple.m4a-audio";    NSString* fileName = [NSString stringWithFormat:@"%@.mov", @"overMix"];        NSString *exportFile = [NSString stringWithFormat:@"%@/%@", [self getLibarayPath], fileName];        // set up export    if ([[NSFileManager defaultManager] fileExistsAtPath:exportFile]) {        [[NSFileManager defaultManager] removeItemAtPath:exportFile error:nil];    }    NSLog(@"是否在主线程1 %d",[NSThread isMainThread]);    NSLog(@"输出路径===%@",exportFile);        NSURL *exportURL = [NSURL fileURLWithPath:exportFile];    exporter.outputURL = exportURL;    self.mixURL = exportURL;        // do the export    [exporter exportAsynchronouslyWithCompletionHandler:^{        int exportStatus = exporter.status;        switch (exportStatus) {            case AVAssetExportSessionStatusFailed:{                NSError *exportError = exporter.error;                NSLog (@"AVAssetExportSessionStatusFailed: %@", exportError);                break;            }                            case AVAssetExportSessionStatusCompleted: {                NSLog(@"是否在主线程2 %d",[NSThread isMainThread]);                NSLog (@"AVAssetExportSessionStatusCompleted");                                break;            }                            case AVAssetExportSessionStatusUnknown: NSLog (@"AVAssetExportSessionStatusUnknown"); break;            case AVAssetExportSessionStatusExporting: NSLog (@"AVAssetExportSessionStatusExporting"); break;            case AVAssetExportSessionStatusCancelled: NSLog (@"AVAssetExportSessionStatusCancelled"); break;            case AVAssetExportSessionStatusWaiting: NSLog (@"AVAssetExportSessionStatusWaiting"); break;            default:  NSLog (@"didn't get export status"); break;        }    }];}static int numMix = 0;- (void) setUpAndAddAudioAtPath:(NSURL*)assetURL toComposition:(AVMutableComposition *)composition start:(CMTime)start dura:(CMTime)dura offset:(CMTime)offset{        AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil];        AVMutableCompositionTrack *track = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];    AVAssetTrack *sourceAudioTrack = [[songAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];        NSError *error = nil;    BOOL ok = NO;        CMTime startTime = start;    CMTime trackDuration = dura;    CMTimeRange tRange = CMTimeRangeMake(startTime, trackDuration);        //Set Volume    AVMutableAudioMixInputParameters *trackMix = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:track];    if (numMix == 0) {        NSLog(@"音量0.9");        [trackMix setVolume:1.0f atTime:startTime];    }else{        NSLog(@"音量0.2");        [trackMix setVolume:0.05f atTime:startTime];    }    numMix++;    [audioMixParams addObject:trackMix];        //Insert audio into track  //offset CMTimeMake(0, 44100)    ok = [track insertTimeRange:tRange ofTrack:sourceAudioTrack atTime:kCMTimeInvalid error:&error];}#pragma mark - 保存路径- (NSString*)getLibarayPath{    NSFileManager *fileManager = [NSFileManager defaultManager];        NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);NSString* path = [paths objectAtIndex:0];        NSString *movDirectory = [path stringByAppendingPathComponent:@"tmpMovMix"];        [fileManager createDirectoryAtPath:movDirectory withIntermediateDirectories:YES attributes:nil error:nil];    return movDirectory;}#pragma mark - 最后合成总的mov- (void)overMix{    [self.trackArr removeAllObjects];        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{                //整合        AVMutableComposition* mixComposition = [[AVMutableComposition alloc] init];                AVMutableVideoCompositionInstruction * MainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];                AVAsset *item = [AVAsset assetWithURL:self.overUrl];                AVAsset *sound = [AVAsset assetWithURL:self.mixURL];                AVMutableCompositionTrack *firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];                    [firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, item.duration) ofTrack:[[item tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil];                                        AVMutableCompositionTrack *AudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];                [AudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, item.duration) ofTrack:[[sound tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];             //FIXING ORIENTATION//        AVMutableVideoCompositionLayerInstruction *FirstlayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:firstTrack];             [FirstlayerInstruction setOpacity:0.0 atTime:item.duration];        [self.trackArr insertObject:FirstlayerInstruction atIndex:0];        MainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero,item.duration);        MainInstruction.layerInstructions = self.trackArr;        AVMutableVideoComposition *MainCompositionInst = [AVMutableVideoComposition videoComposition];        MainCompositionInst.instructions = [NSArray arrayWithObject:MainInstruction];        MainCompositionInst.frameDuration = CMTimeMake(1, 30);                if (iPhone5) {            MainCompositionInst.renderSize = CGSizeMake(320.0, 568.0);        }else{            MainCompositionInst.renderSize = CGSizeMake(320.0, 480.0);//解决图像问题        }                        NSString* fileName = [NSString stringWithFormat:@"%@.mov", @"over+mix-over2"];        NSString *filePath = [NSString stringWithFormat:@"%@/%@", [self getLibarayPath], fileName];        NSLog(@"输出路径 === %@",filePath);        NSURL *url = [NSURL fileURLWithPath:filePath];                AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];        exporter.outputURL=url;        exporter.outputFileType = AVFileTypeQuickTimeMovie;//        exporter.videoComposition = MainCompositionInst;        exporter.shouldOptimizeForNetworkUse = YES;        [exporter exportAsynchronouslyWithCompletionHandler:^         {             dispatch_async(dispatch_get_main_queue(), ^{                 [self exportDidFinish:exporter];             });         }];            });}#pragma mark - 根据asset累加得到duration- (CMTime)addAllAVAssetDuration:(MovDetailItem *)item{        if (item.num == 1) {        self.allTime = CMTimeAdd(kCMTimeZero, item.asset.duration);    }else{        self.allTime = CMTimeAdd(self.allTime, item.asset.duration);    }        return self.allTime;}


1 1
原创粉丝点击