123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- //
- // FURecordEncoder.h
- // FULive
- //
- // Created by L on 2018/1/15.
- // Copyright © 2018年 L. All rights reserved.
- //
- #import "FURecordEncoder.h"
- @interface FURecordEncoder ()
- @property (nonatomic, strong) AVAssetWriter *writer;//媒体写入对象
- @property (nonatomic, strong) AVAssetWriterInput *videoInput;//视频写入
- @property (nonatomic, strong) AVAssetWriterInput *audioInput;//音频写入
- @property (nonatomic, strong) NSString *path;//写入路径
- @end
- @implementation FURecordEncoder
- - (void)dealloc {
- _writer = nil;
- _videoInput = nil;
- _audioInput = nil;
- _path = nil;
- }
- //WCLRecordEncoder遍历构造器的
- + (FURecordEncoder*)encoderForPath:(NSString*) path Height:(NSInteger) cy width:(NSInteger) cx channels: (int) ch samples:(Float64) rate {
- FURecordEncoder* enc = [FURecordEncoder alloc];
- return [enc initPath:path Height:cy width:cx channels:ch samples:rate];
- }
- //初始化方法
- - (instancetype)initPath:(NSString*)path Height:(NSInteger)cy width:(NSInteger)cx channels:(int)ch samples:(Float64) rate {
- self = [super init];
- if (self) {
- self.path = path;
- //先把路径下的文件给删除掉,保证录制的文件是最新的
- [[NSFileManager defaultManager] removeItemAtPath:self.path error:nil];
- NSURL* url = [NSURL fileURLWithPath:self.path];
- //初始化写入媒体类型为MP4类型
- _writer = [AVAssetWriter assetWriterWithURL:url fileType:AVFileTypeMPEG4 error:nil];
- //使其更适合在网络上播放
- _writer.shouldOptimizeForNetworkUse = YES;
- //初始化视频输出
- [self initVideoInputHeight:cy width:cx];
- //确保采集到rate和ch
- if (rate != 0 && ch != 0) {
- //初始化音频输出
- [self initAudioInputChannels:ch samples:rate];
- }
- }
- return self;
- }
- //初始化视频输入
- - (void)initVideoInputHeight:(NSInteger)cy width:(NSInteger)cx {
- //录制视频的一些配置,分辨率,编码方式等等
- NSDictionary* settings = [NSDictionary dictionaryWithObjectsAndKeys:
- AVVideoCodecH264, AVVideoCodecKey,
- [NSNumber numberWithInteger: cx], AVVideoWidthKey,
- [NSNumber numberWithInteger: cy], AVVideoHeightKey,
- nil];
- //初始化视频写入类
- _videoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings];
- //表明输入是否应该调整其处理为实时数据源的数据
- _videoInput.expectsMediaDataInRealTime = YES;
- //将视频输入源加入
- [_writer addInput:_videoInput];
- }
- //初始化音频输入
- - (void)initAudioInputChannels:(int)ch samples:(Float64)rate {
- //音频的一些配置包括音频各种这里为AAC,音频通道、采样率和音频的比特率
- NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
- [ NSNumber numberWithInt: kAudioFormatMPEG4AAC], AVFormatIDKey,
- [ NSNumber numberWithInt: ch], AVNumberOfChannelsKey,
- [ NSNumber numberWithFloat: rate], AVSampleRateKey,
- [ NSNumber numberWithInt: 128000], AVEncoderBitRateKey,
- nil];
- //初始化音频写入类
- _audioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:settings];
- //表明输入是否应该调整其处理为实时数据源的数据
- _audioInput.expectsMediaDataInRealTime = YES;
- //将音频输入源加入
- [_writer addInput:_audioInput];
-
- }
- //完成视频录制时调用
- - (void)finishWithCompletionHandler:(void (^)(void))handler {
- NSLog(@"--------------%ld",(long)_writer.status);
- if (_writer.status == AVAssetWriterStatusWriting) {
- [_writer finishWritingWithCompletionHandler:handler];
- }
- }
- //通过这个方法写入数据
- - (BOOL)encodeFrame:(CMSampleBufferRef) sampleBuffer isVideo:(BOOL)isVideo {
- //数据是否准备写入
- if (CMSampleBufferDataIsReady(sampleBuffer)) {
- //写入状态为未知,保证视频先写入
- if (_writer.status == AVAssetWriterStatusUnknown && isVideo) {
- //获取开始写入的CMTime
- CMTime startTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
- //开始写入
- [_writer startWriting];
- [_writer startSessionAtSourceTime:startTime];
- NSLog(@"-------写----");
- }
- //写入失败
- if (_writer.status == AVAssetWriterStatusFailed) {
- NSLog(@"writer error %@", _writer.error.localizedDescription);
- return NO;
- }
- //判断是否是视频
- if (isVideo) {
- //视频输入是否准备接受更多的媒体数据
- if (_videoInput.readyForMoreMediaData == YES) {
- //拼接数据
- [_videoInput appendSampleBuffer:sampleBuffer];
- return YES;
- }
- }else {
- //音频输入是否准备接受更多的媒体数据
- if (_audioInput.readyForMoreMediaData) {
- //拼接数据
- [_audioInput appendSampleBuffer:sampleBuffer];
- return YES;
- }
- }
- }
- return NO;
- }
- @end
|