KSYUIRecorderKit.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. //
  2. // KSYUIRecorderKit.m
  3. // playerRecorder
  4. //
  5. // Created by ksyun on 16/10/26.
  6. // Copyright © 2016年 ksyun. All rights reserved.
  7. //
  8. #import "KSYUIRecorderKit.h"
  9. #import <libksygpulive/KSYGPUPicMixer.h>
  10. #import <libksygpulive/KSYAudioMixer.h>
  11. #import <libksygpulive/KSYGPUPicOutput.h>
  12. #import <libksygpulive/KSYMoviePlayerController.h>
  13. #import <libksygpulive/KSYDummyAudioSource.h>
  14. @interface KSYUIRecorderKit()
  15. {
  16. BOOL _bBackground;
  17. }
  18. //图层0 player
  19. @property GPUImageTextureInput* textureInput;
  20. @property NSInteger playerLayer;
  21. //图层1 UI
  22. @property GPUImageUIElement* uiElementInput;
  23. @property NSInteger uiLayer;
  24. //混流器
  25. @property KSYGPUPicMixer* uiMixer;
  26. @property KSYAudioMixer *aMixer;
  27. @property KSYDummyAudioSource* dummyAudio;
  28. @property (nonatomic, readonly) int dummyTrack;
  29. @property (nonatomic, readonly) int playerTrack;
  30. @property KSYGPUPicOutput* gpuToStr;
  31. @property CMTime lastPts;
  32. @property (nonatomic) KSYPlayRecordScheme scheme;
  33. @end
  34. @implementation KSYUIRecorderKit
  35. - (instancetype)init {
  36. if (!(self = [super init]))
  37. {
  38. return nil;
  39. }
  40. _bPlayRecord = NO;
  41. CGSize sz = [UIScreen mainScreen].bounds.size;
  42. _contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, sz.width,sz.height)];
  43. _contentView.backgroundColor = [UIColor clearColor];
  44. _contentView.contentScaleFactor = 2;
  45. _playerLayer = 0 ;
  46. _uiLayer = 1;
  47. _dummyTrack = 0;
  48. _playerTrack = 1;
  49. _bBackground = NO;
  50. [self createWriter];
  51. [self createAudioMixer];
  52. [self createVideoMixer];
  53. [self registerApplicationObservers];
  54. return self;
  55. }
  56. - (instancetype) initWithScheme:(KSYPlayRecordScheme)scheme{
  57. _scheme = scheme;
  58. if(_scheme == KSYPlayerRecord_PicMix_Scheme)
  59. return [self init];
  60. else if(_scheme == KSYPlayerRecord_ScreenShot_Scheme)
  61. {
  62. _bPlayRecord = NO;
  63. _dummyTrack = 0;
  64. _playerTrack = 1;
  65. _bBackground = NO;
  66. [self createWriter];
  67. [self createAudioMixer];
  68. [self registerApplicationObservers];
  69. return self;
  70. }
  71. return nil;
  72. }
  73. -(void)dealloc{
  74. if(_contentView)
  75. _contentView = nil;
  76. if(_uiElementInput)
  77. _uiElementInput = nil;
  78. if(_uiMixer){
  79. [_uiMixer clearPicOfLayer:_playerLayer];
  80. [_uiMixer clearPicOfLayer:_uiLayer];
  81. _uiMixer = nil;
  82. }
  83. if(_aMixer)
  84. _aMixer = nil;
  85. if(_gpuToStr)
  86. _gpuToStr = nil;
  87. if(_writer){
  88. [_writer stopWrite];
  89. _writer = nil;
  90. }
  91. if(_dummyAudio){
  92. [_dummyAudio stop];
  93. _dummyAudio = nil;
  94. }
  95. [self unregisterApplicationObservers];
  96. }
  97. -(void)startRecord:(NSURL*) path
  98. {
  99. if(_writer && _bPlayRecord == NO)
  100. {
  101. [_writer startWrite:path];
  102. _bPlayRecord = YES;
  103. }
  104. }
  105. -(void)stopRecord
  106. {
  107. if(_writer && _bPlayRecord == YES)
  108. {
  109. [_writer stopWrite];
  110. _bPlayRecord = NO;
  111. }
  112. }
  113. -(void)createWriter{
  114. if(!_writer)
  115. {
  116. _writer = [[KSYMovieWriter alloc] init];
  117. _writer.videoCodec = KSYVideoCodec_VT264;
  118. _writer.audioCodec = KSYAudioCodec_AAC;
  119. _writer.bWithVideo = YES;
  120. _writer.bWithAudio = YES;
  121. }
  122. }
  123. -(void)createVideoMixer{
  124. if(!_uiMixer)
  125. {
  126. _uiMixer = [[KSYGPUPicMixer alloc] init];
  127. _uiMixer.masterLayer = _uiLayer;
  128. [_uiMixer setPicRect:CGRectMake(-1,-1,0.0,0.0) ofLayer:_playerLayer];
  129. [_uiMixer setPicRotation:kGPUImageFlipVertical ofLayer:_playerLayer];
  130. [_uiMixer setPicAlpha:1.0 ofLayer:_playerLayer];
  131. [_uiMixer setPicRect:CGRectMake(0,0,1.0,1.0) ofLayer:_uiLayer];
  132. [_uiMixer setPicAlpha:1.0 ofLayer:_uiLayer];
  133. }
  134. if(!_gpuToStr)
  135. {
  136. _gpuToStr = [[KSYGPUPicOutput alloc] initWithOutFmt:kCVPixelFormatType_32BGRA];
  137. __weak KSYUIRecorderKit * weakKit = self;
  138. _gpuToStr.videoProcessingCallback = ^(CVPixelBufferRef pixelBuffer, CMTime timeInfo){
  139. [weakKit.writer processVideoPixelBuffer:pixelBuffer timeInfo:timeInfo];
  140. };
  141. [_uiMixer addTarget:_gpuToStr];
  142. }
  143. }
  144. -(void)createAudioMixer{
  145. if(!_aMixer)
  146. {
  147. _aMixer = [[KSYAudioMixer alloc]init];
  148. _aMixer.mainTrack = _dummyTrack;
  149. [_aMixer setTrack:_dummyTrack enable:YES];
  150. [_aMixer setTrack:_playerTrack enable:YES];
  151. __weak KSYUIRecorderKit * weakKit = self;
  152. _aMixer.audioProcessingCallback = ^(CMSampleBufferRef buf){
  153. [weakKit.writer processAudioSampleBuffer:buf];
  154. };
  155. AudioStreamBasicDescription format;
  156. memset(&format, 0, sizeof(format));
  157. format.mSampleRate = 44100;
  158. format.mFormatID = kAudioFormatLinearPCM;
  159. format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
  160. format.mChannelsPerFrame = 2;
  161. format.mBitsPerChannel = 16;
  162. format.mBytesPerFrame = (format.mBitsPerChannel * format.mChannelsPerFrame / 8);
  163. format.mFramesPerPacket = 1;
  164. format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;
  165. _dummyAudio = [[KSYDummyAudioSource alloc]initWithAudioFmt:format];
  166. _dummyAudio.audioProcessingCallback = ^(CMSampleBufferRef sampleBuffer){
  167. [weakKit.aMixer processAudioSampleBuffer:sampleBuffer of:weakKit.dummyTrack];
  168. weakKit.lastPts = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
  169. };
  170. CMTime startPts = CMTimeMake((int64_t)(0 * 1000), 1000);
  171. [_dummyAudio startAt:startPts];
  172. }
  173. }
  174. -(void) processAudioSampleBuffer:(CMSampleBufferRef) buf
  175. {
  176. @synchronized (self) {
  177. if(!_bPlayRecord || !_aMixer)
  178. return;
  179. [_aMixer processAudioSampleBuffer:buf of:_playerTrack];
  180. }
  181. }
  182. -(void) processVideoSampleBuffer:(CVPixelBufferRef)pixelBuffer timeInfo:(CMTime)timeStamp
  183. {
  184. @synchronized (self) {
  185. if(!_writer || !_bPlayRecord || _bBackground || _scheme != KSYPlayerRecord_ScreenShot_Scheme)
  186. return;
  187. CMTime pts = timeStamp;
  188. if(!CMTIME_IS_VALID(pts))
  189. pts = _lastPts;
  190. [_writer processVideoPixelBuffer:pixelBuffer timeInfo:pts];
  191. }
  192. }
  193. -(void) processWithTextureId:(GLuint)InputTexture
  194. TextureSize:(CGSize)TextureSize
  195. Time:(CMTime)time
  196. {
  197. @synchronized (self) {
  198. if(!_bPlayRecord || _bBackground || _scheme != KSYPlayerRecord_PicMix_Scheme)
  199. return;
  200. if(_uiMixer)//_uiMixer是混流器
  201. {
  202. //图层0,视频层
  203. _textureInput = [[GPUImageTextureInput alloc]initWithTexture:InputTexture size:TextureSize];
  204. //清除_playerLayer层的画面内容
  205. [_uiMixer clearPicOfLayer:_playerLayer];
  206. [_textureInput addTarget:_uiMixer atTextureLocation:_playerLayer];
  207. [_textureInput processTextureWithFrameTime:time];
  208. _uiElementInput = [[GPUImageUIElement alloc] initWithView:_contentView];
  209. [_uiMixer clearPicOfLayer:_uiLayer];
  210. [_uiElementInput addTarget:_uiMixer atTextureLocation:_uiLayer];
  211. [_uiElementInput updateWithTimestamp:_lastPts];
  212. }
  213. }
  214. }
  215. - (void)registerApplicationObservers
  216. {
  217. [[NSNotificationCenter defaultCenter] addObserver:self
  218. selector:@selector(applicationWillEnterForeground)
  219. name:UIApplicationWillEnterForegroundNotification
  220. object:nil];
  221. [[NSNotificationCenter defaultCenter] addObserver:self
  222. selector:@selector(applicationDidBecomeActive)
  223. name:UIApplicationDidBecomeActiveNotification
  224. object:nil];
  225. [[NSNotificationCenter defaultCenter] addObserver:self
  226. selector:@selector(applicationWillResignActive)
  227. name:UIApplicationWillResignActiveNotification
  228. object:nil];
  229. [[NSNotificationCenter defaultCenter] addObserver:self
  230. selector:@selector(applicationDidEnterBackground)
  231. name:UIApplicationDidEnterBackgroundNotification
  232. object:nil];
  233. [[NSNotificationCenter defaultCenter] addObserver:self
  234. selector:@selector(applicationWillTerminate)
  235. name:UIApplicationWillTerminateNotification
  236. object:nil];
  237. }
  238. - (void)unregisterApplicationObservers
  239. {
  240. [[NSNotificationCenter defaultCenter] removeObserver:self
  241. name:UIApplicationWillEnterForegroundNotification
  242. object:nil];
  243. [[NSNotificationCenter defaultCenter] removeObserver:self
  244. name:UIApplicationDidBecomeActiveNotification
  245. object:nil];
  246. [[NSNotificationCenter defaultCenter] removeObserver:self
  247. name:UIApplicationWillResignActiveNotification
  248. object:nil];
  249. [[NSNotificationCenter defaultCenter] removeObserver:self
  250. name:UIApplicationDidEnterBackgroundNotification
  251. object:nil];
  252. [[NSNotificationCenter defaultCenter] removeObserver:self
  253. name:UIApplicationWillTerminateNotification
  254. object:nil];
  255. }
  256. - (void)applicationWillEnterForeground
  257. {
  258. _bBackground = NO;
  259. }
  260. - (void)applicationDidBecomeActive
  261. {
  262. _bBackground = NO;
  263. }
  264. - (void)applicationWillResignActive
  265. {
  266. _bBackground = YES;
  267. }
  268. - (void)applicationDidEnterBackground
  269. {
  270. _bBackground = YES;
  271. }
  272. - (void)applicationWillTerminate
  273. {
  274. _bBackground = YES;
  275. }
  276. @end