YOUPAIXLVideoShotTool.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. //
  2. // YOUPAIXLVideoShotTool.m
  3. // XLChat
  4. //
  5. // Created by 张灿 on 2018/2/4.
  6. // Copyright © 2018年 张灿. All rights reserved.
  7. //
  8. #import "YOUPAIXLVideoShotTool.h"
  9. #import "YOUPAIAGVideoBuffer.h"
  10. #import "libyuv.h"
  11. @interface YOUPAIXLVideoShotTool ()
  12. @property (assign, nonatomic) BOOL isPushing,isUpload;
  13. @property (strong, nonatomic) YOUPAIAGVideoBuffer *localVideoBuffer;
  14. @property (strong, nonatomic) YOUPAIAGVideoBuffer *remoteVideoBuffer;
  15. @property (strong, nonatomic) dispatch_source_t videoPublishTimer;
  16. @property (strong, nonatomic) dispatch_source_t uploadPublishTimer;
  17. @end
  18. @implementation YOUPAIXLVideoShotTool
  19. + (YOUPAIXLVideoShotTool *)sharedPusher
  20. {
  21. static YOUPAIXLVideoShotTool *sharedPusher = nil;
  22. static dispatch_once_t onceToken;
  23. dispatch_once(&onceToken, ^{
  24. sharedPusher = [[YOUPAIXLVideoShotTool alloc] init];
  25. sharedPusher.shotImageArray = [NSMutableArray array];
  26. sharedPusher.shotImageSem = dispatch_semaphore_create(1);
  27. });
  28. return sharedPusher;
  29. }
  30. + (dispatch_queue_t)sharedQueue
  31. {
  32. static dispatch_queue_t queue = nil;
  33. static dispatch_once_t onceToken;
  34. dispatch_once(&onceToken, ^{
  35. queue = dispatch_queue_create("cn.sharesmile.ShotQueue", NULL);
  36. });
  37. return queue;
  38. }
  39. + (void)start
  40. {
  41. [[self sharedPusher] start];
  42. }
  43. + (void)stop
  44. {
  45. [[self sharedPusher] stop];
  46. }
  47. - (void)start
  48. {
  49. if (self.isPushing) {
  50. return;
  51. }
  52. self.isPushing = YES;
  53. self.isUpload =YES;
  54. __block int timeout =0;
  55. __block int checkTime =0;
  56. WeakSelf;
  57. // dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  58. // dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,[YOUPAIXLVideoShotTool sharedQueue]);
  59. _videoPublishTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,[YOUPAIXLVideoShotTool sharedQueue]);
  60. // self.videoPublishTimer = timer;
  61. __block NSMutableArray *startArray = [[self.periodArray valueForKeyPath:@"start"] mutableCopy];
  62. __block NSMutableArray *endArray = [[self.periodArray valueForKeyPath:@"end"] mutableCopy];
  63. dispatch_source_set_timer(_videoPublishTimer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒执行
  64. dispatch_source_set_event_handler(_videoPublishTimer, ^{
  65. // timeout++;
  66. //add by leo period 检测周期 shotcycle 截图周期
  67. __strong typeof (weakSelf)strongSelf = weakSelf;
  68. #ifdef OLOPornCheck
  69. if (strongSelf.period==0) {
  70. if (timeout%weakSelf.shotCycle==0 ) {
  71. [strongSelf shotImage];
  72. }
  73. }else{
  74. if(timeout<2*strongSelf.period)
  75. {
  76. if(timeout<=strongSelf.period)
  77. {
  78. if(timeout!=0&&timeout%strongSelf.shotCycle==0)
  79. {
  80. [strongSelf shotImage];
  81. }
  82. }
  83. }
  84. else if((timeout/strongSelf.period)%2==0)
  85. {
  86. checkTime = timeout / strongSelf.period;
  87. if(timeout!=strongSelf.period*checkTime)
  88. {
  89. if((timeout%strongSelf.period)%strongSelf.shotCycle==0)
  90. {
  91. [strongSelf shotImage];
  92. }
  93. }
  94. }
  95. else if(timeout%strongSelf.period==0)
  96. {
  97. if((strongSelf.period)%strongSelf.shotCycle==0)
  98. {
  99. [strongSelf shotImage];
  100. }
  101. }
  102. }
  103. #endif
  104. if(startArray!=nil&&startArray.count>0) {
  105. NSInteger startTime = [[startArray objectAtIndex:0] integerValue];
  106. NSInteger endTime = [[endArray objectAtIndex:0] integerValue];
  107. if(timeout>startTime&&(timeout%startTime)%strongSelf.shotCycle==0&&timeout<endTime) {
  108. [strongSelf shotImage];
  109. }
  110. else if(timeout>endTime)
  111. {
  112. [startArray removeObjectAtIndex:0];
  113. [endArray removeObjectAtIndex:0];
  114. }
  115. }
  116. timeout++;
  117. });
  118. dispatch_resume(_videoPublishTimer);
  119. }
  120. - (void)stop
  121. {
  122. if (!self.isPushing) {
  123. return;
  124. }
  125. dispatch_source_cancel(self.videoPublishTimer);
  126. self.videoPublishTimer = nil;
  127. // self.uploadPublishTimer = nil;
  128. self.isPushing = NO;
  129. [self.shotImageArray removeAllObjects];
  130. }
  131. #pragma mark add video data
  132. + (void)youpaifaddLocalYBuffer:(void *)yBuffer uBuffer:(void *)uBuffer vBuffer:(void *)vBuffer
  133. yStride:(int)yStride uStride:(int)uStride vStride:(int)vStride
  134. width:(int)width height:(int)height
  135. rotation:(int)rotation
  136. {
  137. [[self sharedPusher] youpaifaddLocalYBuffer:yBuffer uBuffer:uBuffer vBuffer:vBuffer yStride:yStride uStride:uStride vStride:vStride width:width height:height rotation:rotation];
  138. }
  139. + (void)youpaifaddRemoteOfUId:(unsigned int)uid
  140. yBuffer:(void *)yBuffer uBuffer:(void *)uBuffer vBuffer:(void *)vBuffer
  141. yStride:(int)yStride uStride:(int)uStride vStride:(int)vStride
  142. width:(int)width height:(int)height
  143. rotation:(int)rotation
  144. {
  145. [[self sharedPusher] youpaifaddRemoteOfUId:uid yBuffer:yBuffer uBuffer:uBuffer vBuffer:vBuffer yStride:yStride uStride:uStride vStride:vStride width:width height:height rotation:rotation];
  146. }
  147. - (void)youpaifaddLocalYBuffer:(void *)yBuffer uBuffer:(void *)uBuffer vBuffer:(void *)vBuffer
  148. yStride:(int)yStride uStride:(int)uStride vStride:(int)vStride
  149. width:(int)width height:(int)height
  150. rotation:(int)rotation
  151. {
  152. YOUPAIAGVideoBuffer *buffer = [[YOUPAIAGVideoBuffer alloc] initWithUId:0 yBuffer:yBuffer uBuffer:uBuffer vBuffer:vBuffer yStride:yStride uStride:uStride vStride:vStride width:width height:height rotation:rotation];
  153. dispatch_async([YOUPAIXLVideoShotTool sharedQueue], ^{
  154. if (self.localVideoBuffer != nil && self.localVideoBuffer.width == width && self.localVideoBuffer.height == height) {
  155. [self.localVideoBuffer youpaifupdateWithYBuffer:buffer.yBuffer uBuffer:buffer.uBuffer vBuffer:buffer.vBuffer yStride:buffer.yStride uStride:buffer.uStride vStride:buffer.vStride width:buffer.width height:buffer.height rotation:buffer.rotation];
  156. } else {
  157. self.localVideoBuffer = buffer;
  158. }
  159. });
  160. }
  161. - (void)youpaifaddRemoteOfUId:(unsigned int)uid
  162. yBuffer:(void *)yBuffer uBuffer:(void *)uBuffer vBuffer:(void *)vBuffer
  163. yStride:(int)yStride uStride:(int)uStride vStride:(int)vStride
  164. width:(int)width height:(int)height
  165. rotation:(int)rotation
  166. {
  167. // NSLog(@"youpaifaddRemoteOfUId CALLBALCK\n");
  168. return;
  169. dispatch_semaphore_wait(self.shotImageSem, DISPATCH_TIME_FOREVER);
  170. self.remoteVideoBuffer = [[YOUPAIAGVideoBuffer alloc] initWithUId:0 yBuffer:yBuffer uBuffer:uBuffer vBuffer:vBuffer yStride:yStride uStride:uStride vStride:vStride width:width height:height rotation:rotation];
  171. dispatch_semaphore_signal(self.shotImageSem);
  172. // dispatch_async([YOUPAIXLVideoShotTool sharedQueue], ^{
  173. // if (self.remoteVideoBuffer != nil && self.remoteVideoBuffer.width == width && self.remoteVideoBuffer.height == height) {
  174. // [self.remoteVideoBuffer youpaifupdateWithYBuffer:buffer.yBuffer uBuffer:buffer.uBuffer vBuffer:buffer.vBuffer yStride:buffer.yStride uStride:buffer.uStride vStride:buffer.vStride width:buffer.width height:buffer.height rotation:buffer.rotation];
  175. // } else {
  176. // self.remoteVideoBuffer = buffer;
  177. // }
  178. // });
  179. }
  180. -(void)shotImage {
  181. //modify by leo
  182. dispatch_async(dispatch_get_main_queue(), ^{
  183. UIImage *image = [UIImage screenView:self.localVideo];
  184. //UIImage *image= [UIImage imageNamed:@"jianhuang"];
  185. NSLog(@"上传截图");
  186. NSDate * newData = [NSDate date];
  187. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  188. [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  189. NSString* dataString = [dateFormatter stringFromDate:newData];
  190. NSLog(@"截图时间 is %@\n",dataString);
  191. if(self->_isUpload) {
  192. [self youpaifuploadImage:image];
  193. // [self SavePhotoLibary:image];
  194. }
  195. // self.remoteVideoBuffer = nil;
  196. });
  197. }
  198. #pragma mark - 访问相册
  199. -(void)SavePhotoLibary:(UIImage *)image{
  200. if(@available(iOS 11.0, *))
  201. {
  202. [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status)
  203. {
  204. if (status == PHAuthorizationStatusNotDetermined || status == PHAuthorizationStatusAuthorized) {
  205. [self loadImageFinished:image];
  206. }else
  207. {
  208. // [ZCHUDHelper showTitle:@"请给予相册保存权限" showtime:2];
  209. return ;
  210. }
  211. }];
  212. }
  213. else
  214. {
  215. PHAuthorizationStatus authStatus = [PHPhotoLibrary authorizationStatus];
  216. if (authStatus == PHAuthorizationStatusRestricted|| authStatus == PHAuthorizationStatusDenied)
  217. {
  218. // [ZCHUDHelper showTitle:@"请给予相册保存权限" showtime:2];
  219. return;
  220. }
  221. else{
  222. [self loadImageFinished:image];
  223. }
  224. }
  225. }
  226. - (void)loadImageFinished:(UIImage *)image
  227. {
  228. [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
  229. //写入图片到相册
  230. [PHAssetChangeRequest creationRequestForAssetFromImage:image];
  231. } completionHandler:^(BOOL success, NSError * _Nullable error) {
  232. NSLog(@"success = %d, error = %@", success, error);
  233. if(success){
  234. dispatch_async(dispatch_get_main_queue(), ^{
  235. // [ZCHUDHelper showTitle:@"保存成功" showtime:1];
  236. });
  237. }
  238. }];
  239. }
  240. - (void)shotImage2{
  241. dispatch_semaphore_wait(self.shotImageSem, DISPATCH_TIME_FOREVER);
  242. if(self.remoteVideoBuffer){
  243. //add by leo for test
  244. NSLog(@"shotImage called \n");
  245. int retomeYBufferSize = self.remoteVideoBuffer.yStride * self.remoteVideoBuffer.height;
  246. int retomeUBufferSize = self.remoteVideoBuffer.uStride * self.remoteVideoBuffer.height / 2;
  247. int retomeVBufferSize = self.remoteVideoBuffer.vStride * self.remoteVideoBuffer.height / 2;
  248. unsigned char *retomeYBuffer = [YOUPAIAGVideoBuffer copy:self.remoteVideoBuffer.yBuffer size:retomeYBufferSize];
  249. unsigned char *retomeUBuffer = [YOUPAIAGVideoBuffer copy:self.remoteVideoBuffer.uBuffer size:retomeUBufferSize];
  250. unsigned char *retomeVBuffer = [YOUPAIAGVideoBuffer copy:self.remoteVideoBuffer.vBuffer size:retomeVBufferSize];
  251. NSLog(@"retomeUBuffer is %s",retomeUBuffer);
  252. //rotate local
  253. unsigned char *rotatedretomeYBuffer = malloc(retomeYBufferSize);
  254. unsigned char *rotatedretomeUBuffer = malloc(retomeUBufferSize);
  255. unsigned char *rotatedretomeVBuffer = malloc(retomeVBufferSize);
  256. I420Rotate(retomeYBuffer, self.remoteVideoBuffer.yStride,
  257. retomeUBuffer, self.remoteVideoBuffer.uStride,
  258. retomeVBuffer, self.remoteVideoBuffer.vStride,
  259. rotatedretomeYBuffer, self.remoteVideoBuffer.height,
  260. rotatedretomeUBuffer, self.remoteVideoBuffer.height/2,
  261. rotatedretomeVBuffer, self.remoteVideoBuffer.height/2,
  262. self.remoteVideoBuffer.height, self.remoteVideoBuffer.width, self.remoteVideoBuffer.rotation);
  263. free(retomeYBuffer);
  264. free(retomeUBuffer);
  265. free(retomeVBuffer);
  266. int dataLength = retomeYBufferSize + retomeUBufferSize + retomeVBufferSize;
  267. unsigned char *youpaifyuvData = malloc(dataLength);
  268. memcpy(youpaifyuvData, rotatedretomeYBuffer, retomeYBufferSize);
  269. memcpy(youpaifyuvData + retomeYBufferSize, rotatedretomeUBuffer, retomeUBufferSize);
  270. memcpy(youpaifyuvData + retomeYBufferSize + retomeUBufferSize, rotatedretomeVBuffer, retomeVBufferSize);
  271. UIImage* image =[self makeUIImage:self.remoteVideoBuffer];
  272. [self youpaifuploadImage:image];
  273. free(youpaifyuvData);
  274. free(rotatedretomeYBuffer);
  275. free(rotatedretomeUBuffer);
  276. free(rotatedretomeVBuffer);
  277. self.remoteVideoBuffer = nil;
  278. }
  279. dispatch_semaphore_signal(self.shotImageSem);
  280. }
  281. - (UIImage *)makeUIImage:(YOUPAIAGVideoBuffer*)videoBuffer
  282. {
  283. unsigned char* argb = (unsigned char*)malloc(videoBuffer.width * videoBuffer.height * 4 * sizeof(unsigned char));
  284. I420ToARGB(videoBuffer.yBuffer, videoBuffer.yStride, videoBuffer.uBuffer, videoBuffer.uStride, videoBuffer.vBuffer, videoBuffer.vStride, argb, 4*videoBuffer.width, videoBuffer.width, videoBuffer.height);
  285. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  286. CGContextRef context = CGBitmapContextCreate(argb, videoBuffer.width, videoBuffer.height, 8, videoBuffer.width * 4, colorSpace,
  287. kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
  288. CGImageRef quartzImage = CGBitmapContextCreateImage(context);
  289. CGContextRelease(context);
  290. CGColorSpaceRelease(colorSpace);
  291. UIImage *image = [UIImage imageWithCGImage:quartzImage];
  292. CGImageRelease(quartzImage);
  293. free(argb);
  294. argb = NULL;
  295. return image;
  296. }
  297. - (UIImage *)makeUIImage:(unsigned char *)inBaseAddress
  298. width:(int)inWidth
  299. height:(int)inHeight
  300. {
  301. int scale = 1;
  302. unsigned char* y0 = inBaseAddress;
  303. unsigned char* uv0 = inBaseAddress + inWidth * inHeight * sizeof(unsigned char);
  304. // int outWidth = inWidth / scale;
  305. // int outHeight = inHeight / scale;
  306. inWidth = (inWidth >> 2) << 2;
  307. inHeight = (inHeight >> 2) << 2;
  308. align_buffer_64(sdata, inWidth * inHeight * 1.5 * sizeof(unsigned char));
  309. unsigned char* y1 = sdata;
  310. unsigned char* uv1 = sdata + inWidth * inHeight;
  311. memset(uv1, 128, 0.5 * inWidth * inHeight);
  312. ScalePlane_16((uint16*)uv0, inWidth / 2,
  313. inWidth / 2, inHeight / 2,
  314. (uint16*)uv1, inWidth / 2,
  315. inWidth / 2, inHeight / 2,
  316. kFilterNone);
  317. ScalePlane(y0, inWidth,
  318. inWidth, inHeight,
  319. y1, inWidth,
  320. inWidth, inHeight,
  321. kFilterNone);
  322. unsigned char* argb = (unsigned char*)malloc(inWidth * inHeight * 4 * sizeof(unsigned char));
  323. NV12ToARGB(y1, inWidth, uv1, inWidth, argb, inWidth * 4, inWidth, inHeight);
  324. // int NV12ToARGB(const uint8* src_y, int src_stride_y,
  325. // const uint8* src_uv, int src_stride_uv,
  326. // uint8* dst_argb, int dst_stride_argb,
  327. // int width, int height);
  328. // int I420ToARGB(const uint8* src_y, int src_stride_y,
  329. // const uint8* src_u, int src_stride_u,
  330. // const uint8* src_v, int src_stride_v,
  331. // uint8* dst_argb, int dst_stride_argb,
  332. // int width, int height);
  333. free_aligned_buffer_64(sdata);
  334. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  335. CGContextRef context = CGBitmapContextCreate(argb, inWidth, inHeight, 8, inWidth * 4, colorSpace,
  336. kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
  337. CGImageRef quartzImage = CGBitmapContextCreateImage(context);
  338. CGContextRelease(context);
  339. CGColorSpaceRelease(colorSpace);
  340. UIImage *image = [UIImage imageWithCGImage:quartzImage];
  341. CGImageRelease(quartzImage);
  342. free(argb);
  343. argb = NULL;
  344. return image;
  345. }
  346. - (void)youpaifuploadImage:(UIImage*)image{
  347. NSData *imageData = [UIImage zipNSDataWithImage:image maxFileSize:20*1024];
  348. NSString *encodedImageStr = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
  349. NSMutableDictionary* parm = [NSMutableDictionary dictionary];
  350. [parm setObject:self.room_id forKey:@"room_id"];
  351. [parm setObject:encodedImageStr forKey:@"from"];
  352. //[parm setObject:encodedImageStr forKey:@"to"];
  353. if (self.isFrom) { // 主叫
  354. [parm setObject:self.uid forKey:@"uid"];
  355. }else{ // 被叫
  356. [parm setObject:self.uid forKey:@"uid"];
  357. }
  358. WeakSelf;
  359. [LCHttpHelper requestWithURLString:VideoPornCheck parameters:parm needToken:YES type:(HttpRequestTypePost) success:^(id responseObject) {
  360. NSLog(@"输出🍀VideoPornCheck\n%@",responseObject);
  361. NSDictionary* dict = (NSDictionary*)responseObject;
  362. NSInteger code = [[dict objectForKey:@"code"] integerValue];
  363. if (code==0) {
  364. if ([dict[@"data"][@"is_upload"] integerValue] == 0) {
  365. weakSelf.isUpload = NO;
  366. }
  367. }
  368. } failure:^(NSError *error) {
  369. NSLog(@"输出🍀VideoPornCheck\n%@",error);
  370. }];
  371. }
  372. @end