码迷,mamicode.com
首页 > 移动开发 > 详细

iOS音频视频拼接,视频视频拼接

时间:2019-03-07 17:38:45      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:make   sync   tslib   too   ast   cse   encoder   alc   within   

在一个unity3d项目中加录屏功能,录屏用的第三方ShareREC,由于是声控游戏,关闭了录屏功能的音频,单独录制了声控时候的声音,并且每局游戏的的视频前面加视频广告,这里就牵涉到录屏的视频要加上录声控时候的声音的拼接,及整改游戏视频拼接视频广告。写了个工具类FileTools,里面有对文件的各种操作

#import "FileTools.h"

 

@implementation FileTools

 

+(NSString*)tempDirectory

{

   return  NSTemporaryDirectory();

}

 

+ (NSString *)cacheDirectory

{

    

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);

    return [paths objectAtIndex:0];

}

 

+ (NSString *)documentDirectory

{

    

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    return [paths objectAtIndex:0];

}

 

+ (NSString *)createDirectoryInDocumentDirectory:(NSString *)pathName

{

    NSString *doc = [self documentDirectory];

    NSFileManager *fileHandle = [NSFileManager defaultManager];

    NSString *path = [doc stringByAppendingPathComponent:pathName];

    if(![fileHandle fileExistsAtPath:path]) {

        NSError *error;

        if([fileHandle createDirectoryAtPath:path withIntermediateDirectories:false attributes:nil error:&error]) {

        }

        else {

            return nil;

        }

    }else{//文件夹存在

        NSError *error;

        if( [fileHandle removeItemAtPath:path error:&error]){

 

            if([fileHandle createDirectoryAtPath:path withIntermediateDirectories:false attributes:nil error:&error]) {

 

            }

            else {

                return nil;

            }

        }

    }

    

    return path;

}

 

+ (NSString *)createFileInDocumentDirectory:(NSString *)fileName

{

    

    NSString *doc = [self documentDirectory];

    NSFileManager *fileHandle = [NSFileManager defaultManager];

    NSString *path = [doc stringByAppendingPathComponent:fileName];

    if(![fileHandle fileExistsAtPath:path]) {

        if([fileHandle createFileAtPath:path contents:nil attributes:nil]) {

            

        }

        else {

            return nil;

        }

    }

    return path;

}

 

+ (BOOL)removeFileWithUrl:(NSURL*)fileUrl

{

    NSFileManager *fileManager = [NSFileManager defaultManager];

    

    if (fileUrl) {

        if ( [fileManager removeItemAtURL:fileUrl error:NULL]) {

            return YES;

        }

    }

    

    return NO;

}

 

+ (BOOL)ModifyFileNameWithPath:(NSString*)filePath  toPath:(NSString*)toPath

{

    NSFileManager *fm = [NSFileManager defaultManager];

    NSError *error;

    BOOL isSuccess;

    isSuccess = [fm moveItemAtPath:filePath toPath:toPath error:&error];

    

    return isSuccess;

}

 

@end

 

然后单独写了个视频声音管理的SoundRecord类,并且这是个单例

 

#import <ShareREC/ShareREC.h>

#import <ShareREC/Extension/ShareREC+Ext.h>

#import  <ShareREC/ShareREC.framework/Headers/Extension/ShareREC+RecordingManager.h>

#import <CoreGraphics/CoreGraphics.h>

#import <AssetsLibrary/ALAsset.h>

#import <AssetsLibrary/ALAssetsLibrary.h>

#import <AssetsLibrary/ALAssetsGroup.h>

#import <AssetsLibrary/ALAssetRepresentation.h>

#import "ShareRecUnity3DExtension.h"

#import "SoundRecord.h"

#import <AVFoundation/AVFoundation.h>

#import "FileTools.h"

 

#define  kAudioFileName @"sound.mp4"

#define kVideoWithSoundFileName @"VideoWithSoundFileName.mp4"

#define kGameName @"shengkongGame"

 

@interface SoundRecord()<AVAudioRecorderDelegate,UIAlertViewDelegate>

 

@property (nonatomic, strong)  AVAudioRecorder * recorder;

@property (nonatomic, strong) AVAudioSession *session;

 

@property (nonatomic,strong) NSTimer *soundTimer;//录音声波监控(注意这里暂时不对播放进行监控)

 

/** 合成视频文件 */

@property (nonatomic, strong) NSURL *outPutUrl;

 

@end

 

@implementation SoundRecord

 

static SoundRecord *_instance;

 

+ (id)allocWithZone:(NSZone *)zone

{

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        

         _instance = [super allocWithZone:zone];

        

     });

    

   return _instance;

}

 

+ (SoundRecord *)sharedInstance

{

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        

      _instance = [[self alloc] init];

  

    });

    

    return _instance;

}

- (instancetype)init

{

    self = [super init];

    if (self) {

 

        self.mergeVideoStatus = 0;

    }

    

    return self;

}

- (void)prepareRecord

{

    // 真机环境下需要的代码

   _session = [AVAudioSession sharedInstance];

    NSError *sessionError;

    //既要播放声音又需要录音

//    [_session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];

    //设置播放器为扬声器模式

//    [_session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];

        [_session setCategory:AVAudioSessionCategoryPlayAndRecord

              withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker

                    error:&sessionError];

    

    if(_session == nil){

        NSLog(@"Error creating session: %@", [sessionError description]);

    }else{

        //苹果推荐显示激活AVAudioSession

        [_session setActive:YES error:nil];

    }

    

    

    // 1.获取沙盒地址

    self.recordFileUrl = [NSURL fileURLWithPath:[FileTools createFileInDocumentDirectory:kAudioFileName]];

    

    // 3.设置录音的一些参数

    NSMutableDictionary *setting = [NSMutableDictionary dictionary];

    // 音频格式

    setting[AVFormatIDKey] = @(kAudioFormatMPEG4AAC);

    // 录音采样率(Hz) 如:AVSampleRateKey==8000/44100/96000(影响音频的质量)

    setting[AVSampleRateKey] = @(44100.0);

    // 音频通道数 1 或 2

    setting[AVNumberOfChannelsKey] = @(1);

    // 线性音频的位深度  8、16、24、32

    setting[AVLinearPCMBitDepthKey] = @(16);

    //录音的质量

    setting[AVEncoderAudioQualityKey] = [NSNumber numberWithInt:AVAudioQualityHigh];

    //是否使用浮点数采样

    setting[AVLinearPCMIsFloatKey] =  @(YES) ;

    

    _recorder = [[AVAudioRecorder alloc] initWithURL:self.recordFileUrl settings:setting error:NULL];

    _recorder.delegate = self;

    [_recorder prepareToRecord];

    _recorder.meteringEnabled = YES;

    

}

 

// 开始录音

- (void)startRecord

{

    self.mergeVideoStatus = 0;

    // 录音时停止播放 删除曾经生成的文件

    [self prepareRecord];

   

     [_recorder record];

     [_recorder updateMeters];

    

    _soundTimer = [NSTimer scheduledTimerWithTimeInterval:0.1

                                                 target:self

                                               selector:@selector(audioPowerChange) userInfo:nil

                                                repeats:YES];

}

 

/**

 *  录音声波状态设置

 */

-(void)audioPowerChange{

    [_recorder updateMeters];//更新测量值

    CGFloat power= [_recorder averagePowerForChannel:0];//取得第一个通道的音频,注意音频强度范围时-160到0

    //转换成0~160  (0是安静,160最大,当然是可以超过160的,超过极限大就超过160)

//    self.power = (power + 160);

    

    //转换最高分贝值,范围是0到1。0最小,1最大。

    self.power = pow(10, (0.05 * power));

 

    NSLog(@"声音分贝 xxxxx == %f",self.power);

 

}

 

//结束录音

- (void)endRecored

{

  

    [_recorder stop];

    _recorder = nil;

    

    if (_soundTimer) {

         [_soundTimer invalidate];

        _soundTimer = nil;

    }

    

    self.power = 0.0;

    

}

 

 

//合成新视频 用没有声音的MP4和录制的声音(返回新视频路径)

- (void)addSoundToVideo:(NSURL*)videoUrl

               soundUrl:(NSURL*)soundUrl

             completion:(void (^)(NSURL*newVideoUrl))handler

{

    // 1 - Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances.

    AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];

    

    AVAsset *videoAsset = [AVAsset assetWithURL:videoUrl];

    // 2 - Video track

    AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo

                                                                        preferredTrackID:kCMPersistentTrackID_Invalid];

 

    [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)

                        ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil];

 

    

    // 3 - Audio track 添加背景音乐的

    AVURLAsset *audioAsset = [[AVURLAsset alloc] initWithURL:soundUrl options:nil];

    AVMutableCompositionTrack *AudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio

                                                                         preferredTrackID:kCMPersistentTrackID_Invalid];

    

    [AudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)

                         ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];

 

    NSString * tmpPath  = NSTemporaryDirectory();

    NSString * filePath = [tmpPath stringByAppendingPathComponent:kVideoWithSoundFileName];

    self.outPutUrl = [NSURL fileURLWithPath:filePath];

    // 5 - Create exporter

    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition

                                                                      presetName:AVAssetExportPresetHighestQuality];

    exporter.outputURL = self.outPutUrl;

    exporter.outputFileType = AVFileTypeQuickTimeMovie;

    exporter.shouldOptimizeForNetworkUse = YES;

    

    [exporter exportAsynchronouslyWithCompletionHandler:^{

        

        //删除录音

        [FileTools removeFileWithUrl:self.recordFileUrl];

        //删除ShareREC录制的视频 (清除所有本地视频)

        [ShareREC clearLocalRecordings];

 

        [self exportDidFinish:self.outPutUrl];

 

//        if(handler){

//            handler(self.outPutUrl);

//        }

        

        

    }];

    

}

 

- (void)exportDidFinish:(NSURL*)outputURL{

    

    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

    

    if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:outputURL]) {

        

        [library writeVideoAtPathToSavedPhotosAlbum:outputURL completionBlock:^(NSURL *assetURL, NSError *error){

            

            //删除合成的临时视频

            [FileTools removeFileWithUrl:outputURL];

            

            dispatch_async(dispatch_get_main_queue(), ^{

                if (error) {

                    

                    self.mergeVideoStatus = 2;

                    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"视频保存相册失败"

                                                                    message:nil

                                                                   delegate:self

                                                          cancelButtonTitle:@"重来一局"

                                                          otherButtonTitles:nil];

                       [alert show];

                    

                } else {

                    

                    self.mergeVideoStatus = 1;

                    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"视频保存相册成功"

                                                                    message:nil

                                                                   delegate:self

                                                          cancelButtonTitle:@"重来一局"

                                                          otherButtonTitles:nil];

                       [alert show];

 

                    

                }

 

            });

 

            

        }];

    }

}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

{

    if (buttonIndex == 0) {

        self.mergeVideoStatus = 3;//重新开始游戏

    }

}

- (void)removeRecordSoundAndVideo

{

    //删除录音

    [FileTools removeFileWithUrl:self.recordFileUrl];

    //删除ShareREC录制的视频 (清除所有本地视频)

    [ShareREC clearLocalRecordings];

}

 

@end

 

好了在用的地方先是c方法,在c方法里面再调用声音控制单例完成

 

#import "ShareRecUnity3DExtension.h"

#import <ShareREC/ShareREC.h>

#import <ShareREC/Extension/ShareREC+Ext.h>

#import  <ShareREC/ShareREC.framework/Headers/Extension/ShareREC+RecordingManager.h>

#import "JSONKit.h"

#import "SoundRecord.h"

 

#if defined (__cplusplus)

extern "C" {

#endif

    

    extern   float __iosXZdB();//小走分贝

    

    extern   float __iosXZSpeed();//小走速度

    

    extern   float __iosDZdB();//大走分贝

    

    extern   float __iosDZSpeed();//大走速度

    

    extern   float __iosXTdB();//小跳分贝

    

    extern   float __iosXTGD();//小跳高度

    

    extern   float __iosDTdB();//大跳分贝

    

    extern   float __iosDTGD();//大跳高度

    

    extern  float __iosGetRecordingdB();//获取当前声音分贝

    

    extern  void __iosStartRecordSound();//开始录音

    

    extern  void __iosEndRecordSound();//结束录音

    

    extern  void __iosStartMergeVideos();//开始合并视频

    

    extern  void __iosRemoveAudioAndVideo();//删除视频

    

    extern  int __iosMergeVideosStatus();//返回视频合成状态(0正在合成,1合成成功,2合成失败)

    

    

    /**

     * @brief 初始化ShareRec

     *

     * @param appKey 应用Key

     */

    extern void __iosShareRECRegisterApp(void *appKey);

    

    /**

     * @brief 开始录制

     */

    extern void __iosShareRECStartRecording();

    

    /**

     * @brief 结束录制

     *

     *  @param  observer    观察回调对象名称

     */

    extern void __iosShareRECStopRecording (void *observer);

    

    /**

     * @brief 播放最后一个录像

     */

    extern void __iosShareRECPlayLastRecording ();

    

    /**

     * @brief 设置码率,默认为800kbps = 800 * 1024

     *

     * @param bitRate 码率

     */

    extern void __iosShareRECSetBitRate (int bitRate);

    

    /**

     * @brief 设置帧率

     *

     * @param fps 帧率

     */

    extern void __iosShareRECSetFPS (int fps);

    

    /**

     * @brief 设置最短录制时间,默认4秒

     *

     * @param time    时间,0表示不限制

     */

    extern void __iosShareRECSetMinimumRecordingTime(float time);

    

    /**

     * @brief 获取最后一个录像的路径

     */

    extern const char* __iosShareRECLastRecordingPath ();

    

    /**

     *  编辑最后一个录像

     *

     *  @param title    标题

     *  @param userData 用户数据

     *  @param observer 回调对象名称

     */

    extern void __iosShareRECEditLastRecording (void *title, void *userData, void *observer);

    

    /**

     *  编辑最后一个录像

     *

     *  @param observer 回调对象名称

     */

    extern void __iosShareRECEditLastRecordingNew (void *observer);

    

    /**

     *  设置是否同步录入语音解说

     *

     *  @param syncAudioComment 同步语音解说标识,YES 表示同步录入, NO 表示不录入。

     */

    extern void __iosShareRECSetSyncAudioComment (bool syncAudioComment);

    

#if defined (__cplusplus)

}

#endif

 

#if defined (__cplusplus)

extern "C" {

#endif

    

    extern void UnitySendMessage(const char* obj, const char* method, const char* msg);

    

    

    float __iosXZdB(){//小走分贝

        return 0.05;

    }

    

    

    float __iosXZSpeed()//小走速度

    {

        return 2;

    }

    

    

    float __iosDZdB()//大走分贝

    {

        return 0.15;

    }

    

    

    float __iosDZSpeed()//大走速度

    {

        return 3;

    }

    

    

    float __iosXTdB()//小跳分贝

    {

        return 0.2;

    }

    

    

    float __iosXTGD()//小跳高度

    {

        return 100;

    }

    

    

    float __iosDTdB()//大跳分贝

    {

        return 0.4;

    }

    

    

    float __iosDTGD()//大跳高度

    {

        return 200;

    }

    

    

    float __iosGetRecordingdB()

    {

        return   [SoundRecord sharedInstance].power;

    }

    

    void __iosStartRecordSound()

    {

        [[SoundRecord sharedInstance] startRecord];

    }

    

    void __iosEndRecordSound()

    {

        [[SoundRecord sharedInstance] endRecored];

    }

    

    void __iosRemoveAudioAndVideo()

    {

        [[SoundRecord sharedInstance] removeRecordSoundAndVideo];

    }

    

    int  __iosMergeVideosStatus()

    {

        return  [SoundRecord sharedInstance].mergeVideoStatus;

        

    }

    

    void __iosStartMergeVideos()

    {

        

        NSURL *gameSoundUrl = [SoundRecord sharedInstance].recordFileUrl;

        

        //               SRERecording * recording =  [[ShareREC  currentLocalRecordings] lastObject];

        

        [[SoundRecord sharedInstance] addSoundToVideo:[NSURL fileURLWithPath: [ShareREC lastRecordingPath]]

                                             soundUrl:gameSoundUrl

                                           completion:nil

         ];

    }

    

    

    

    void __iosShareRECRegisterApp(void *appKey)

    {

        NSString *appKeyStr = nil;

        if (appKey)

        {

            appKeyStr = [NSString stringWithCString:appKey encoding:NSUTF8StringEncoding];

        }

        

        [ShareREC registerApp:appKeyStr];

    }

    

    

    void __iosShareRECStartRecording()

    {

        [ShareREC startRecording];

    }

    

    void __iosShareRECStopRecording (void *observer)

    {

        

        NSString *observerStr = nil;

        if (observer)

        {

            observerStr = [NSString stringWithCString:observer encoding:NSUTF8StringEncoding];

        }

        

        [ShareREC stopRecording:^(NSError *error) {

            

            NSMutableDictionary *resultDict = [NSMutableDictionary dictionaryWithDictionary:@{@"name" : @"StopRecordingFinished"}];

            if (error)

            {

                NSDictionary *errDict = @{@"code" : @(error.code), @"message" : error.localizedDescription ? error.localizedDescription : @""};

                [resultDict setObject:errDict forKey:@"error"];

            }

            

            NSString *resultStr = [resultDict JSONString];

            UnitySendMessage([observerStr UTF8String], "shareRECCallback", [resultStr UTF8String]);

            

            

        }];

    }

    

    void __iosShareRECPlayLastRecording ()

    {

        [ShareREC playLastRecording];

    }

    

    void __iosShareRECSetBitRate (int bitRate)

    {

        [ShareREC setBitRate:bitRate];

    }

    

    void __iosShareRECSetFPS (int fps)

    {

        [ShareREC setFPS:fps];

    }

    

    void __iosShareRECSetMinimumRecordingTime(float time)

    {

        [ShareREC setMinimumRecordingTime:time];

    }

    

    const char* __iosShareRECLastRecordingPath ()

    {

        if ([ShareREC lastRecordingPath])

        {

            return strdup([[ShareREC lastRecordingPath] UTF8String]);

        }

        

        return strdup([@"" UTF8String]);

    }

    

    void __iosShareRECEditLastRecording (void *title, void *userData, void *observer)

    {

        NSString *titleStr = nil;

        if (title)

        {

            titleStr = [NSString stringWithCString:title encoding:NSUTF8StringEncoding];

        }

        

        NSDictionary *userDataDict = nil;

        if (userData)

        {

            NSString *userDataStr = [NSString stringWithCString:userData encoding:NSUTF8StringEncoding];

            userDataDict = [userDataStr objectFromJSONString];

        }

        

        NSString *observerStr = nil;

        if (observer)

        {

            observerStr = [NSString stringWithCString:observer encoding:NSUTF8StringEncoding];

        }

        

        [ShareREC editLastRecordingWithTitle:titleStr userData:userDataDict onClose:^{

            

            NSDictionary *resultDict = @{@"name" : @"SocialClose"};

            NSString *resultStr = [resultDict JSONString];

            UnitySendMessage([observerStr UTF8String], "shareRECCallback", [resultStr UTF8String]);

            

        }];

    }

    

    void __iosShareRECEditLastRecordingNew (void *observer)

    {

        NSString *observerStr = nil;

        if (observer)

        {

            observerStr = [NSString stringWithCString:observer encoding:NSUTF8StringEncoding];

        }

        

        [ShareREC editLastRecording:^(BOOL cancelled) {

            

            NSDictionary *resultDict = @{@"name" : @"EditResult", @"cancelled" : @(cancelled)};

            NSString *resultStr = [resultDict JSONString];

            UnitySendMessage([observerStr UTF8String], "shareRECCallback", [resultStr UTF8String]);

            

        }];

    }

    

    void __iosShareRECSetSyncAudioComment (bool syncAudioComment)

    {

        [ShareREC setSyncAudioComment:syncAudioComment ? YES : NO];

    }

    

#if defined (__cplusplus)

}

#endif

 

@implementation ShareRecUnity3DExtension

 

@end

iOS音频视频拼接,视频视频拼接

标签:make   sync   tslib   too   ast   cse   encoder   alc   within   

原文地址:https://www.cnblogs.com/yeas/p/10490838.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!