标签: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
标签:make sync tslib too ast cse encoder alc within
原文地址:https://www.cnblogs.com/yeas/p/10490838.html