FURecordEncoder.m 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. //
  2. // FURecordEncoder.h
  3. // FULive
  4. //
  5. // Created by L on 2018/1/15.
  6. // Copyright © 2018年 L. All rights reserved.
  7. //
  8. #import "FURecordEncoder.h"
  9. @interface FURecordEncoder ()
  10. @property (nonatomic, strong) AVAssetWriter *writer;//媒体写入对象
  11. @property (nonatomic, strong) AVAssetWriterInput *videoInput;//视频写入
  12. @property (nonatomic, strong) AVAssetWriterInput *audioInput;//音频写入
  13. @property (nonatomic, strong) NSString *path;//写入路径
  14. @end
  15. @implementation FURecordEncoder
  16. - (void)dealloc {
  17. _writer = nil;
  18. _videoInput = nil;
  19. _audioInput = nil;
  20. _path = nil;
  21. }
  22. //WCLRecordEncoder遍历构造器的
  23. + (FURecordEncoder*)encoderForPath:(NSString*) path Height:(NSInteger) cy width:(NSInteger) cx channels: (int) ch samples:(Float64) rate {
  24. FURecordEncoder* enc = [FURecordEncoder alloc];
  25. return [enc initPath:path Height:cy width:cx channels:ch samples:rate];
  26. }
  27. //初始化方法
  28. - (instancetype)initPath:(NSString*)path Height:(NSInteger)cy width:(NSInteger)cx channels:(int)ch samples:(Float64) rate {
  29. self = [super init];
  30. if (self) {
  31. self.path = path;
  32. //先把路径下的文件给删除掉,保证录制的文件是最新的
  33. [[NSFileManager defaultManager] removeItemAtPath:self.path error:nil];
  34. NSURL* url = [NSURL fileURLWithPath:self.path];
  35. //初始化写入媒体类型为MP4类型
  36. _writer = [AVAssetWriter assetWriterWithURL:url fileType:AVFileTypeMPEG4 error:nil];
  37. //使其更适合在网络上播放
  38. _writer.shouldOptimizeForNetworkUse = YES;
  39. //初始化视频输出
  40. [self initVideoInputHeight:cy width:cx];
  41. //确保采集到rate和ch
  42. if (rate != 0 && ch != 0) {
  43. //初始化音频输出
  44. [self initAudioInputChannels:ch samples:rate];
  45. }
  46. }
  47. return self;
  48. }
  49. //初始化视频输入
  50. - (void)initVideoInputHeight:(NSInteger)cy width:(NSInteger)cx {
  51. //录制视频的一些配置,分辨率,编码方式等等
  52. NSDictionary* settings = [NSDictionary dictionaryWithObjectsAndKeys:
  53. AVVideoCodecH264, AVVideoCodecKey,
  54. [NSNumber numberWithInteger: cx], AVVideoWidthKey,
  55. [NSNumber numberWithInteger: cy], AVVideoHeightKey,
  56. nil];
  57. //初始化视频写入类
  58. _videoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings];
  59. //表明输入是否应该调整其处理为实时数据源的数据
  60. _videoInput.expectsMediaDataInRealTime = YES;
  61. //将视频输入源加入
  62. [_writer addInput:_videoInput];
  63. }
  64. //初始化音频输入
  65. - (void)initAudioInputChannels:(int)ch samples:(Float64)rate {
  66. //音频的一些配置包括音频各种这里为AAC,音频通道、采样率和音频的比特率
  67. NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
  68. [ NSNumber numberWithInt: kAudioFormatMPEG4AAC], AVFormatIDKey,
  69. [ NSNumber numberWithInt: ch], AVNumberOfChannelsKey,
  70. [ NSNumber numberWithFloat: rate], AVSampleRateKey,
  71. [ NSNumber numberWithInt: 128000], AVEncoderBitRateKey,
  72. nil];
  73. //初始化音频写入类
  74. _audioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:settings];
  75. //表明输入是否应该调整其处理为实时数据源的数据
  76. _audioInput.expectsMediaDataInRealTime = YES;
  77. //将音频输入源加入
  78. [_writer addInput:_audioInput];
  79. }
  80. //完成视频录制时调用
  81. - (void)finishWithCompletionHandler:(void (^)(void))handler {
  82. NSLog(@"--------------%ld",(long)_writer.status);
  83. if (_writer.status == AVAssetWriterStatusWriting) {
  84. [_writer finishWritingWithCompletionHandler:handler];
  85. }
  86. }
  87. //通过这个方法写入数据
  88. - (BOOL)encodeFrame:(CMSampleBufferRef) sampleBuffer isVideo:(BOOL)isVideo {
  89. //数据是否准备写入
  90. if (CMSampleBufferDataIsReady(sampleBuffer)) {
  91. //写入状态为未知,保证视频先写入
  92. if (_writer.status == AVAssetWriterStatusUnknown && isVideo) {
  93. //获取开始写入的CMTime
  94. CMTime startTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
  95. //开始写入
  96. [_writer startWriting];
  97. [_writer startSessionAtSourceTime:startTime];
  98. NSLog(@"-------写----");
  99. }
  100. //写入失败
  101. if (_writer.status == AVAssetWriterStatusFailed) {
  102. NSLog(@"writer error %@", _writer.error.localizedDescription);
  103. return NO;
  104. }
  105. //判断是否是视频
  106. if (isVideo) {
  107. //视频输入是否准备接受更多的媒体数据
  108. if (_videoInput.readyForMoreMediaData == YES) {
  109. //拼接数据
  110. [_videoInput appendSampleBuffer:sampleBuffer];
  111. return YES;
  112. }
  113. }else {
  114. //音频输入是否准备接受更多的媒体数据
  115. if (_audioInput.readyForMoreMediaData) {
  116. //拼接数据
  117. [_audioInput appendSampleBuffer:sampleBuffer];
  118. return YES;
  119. }
  120. }
  121. }
  122. return NO;
  123. }
  124. @end