CoolFlutterIJK.m 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. //
  2. // Created by Caijinglong on 2019-03-08.
  3. //
  4. #import "CoolFlutterIJK.h"
  5. #import "CoolVideoInfo.h"
  6. #import "CoolIjkNotifyChannel.h"
  7. #import <IJKMediaFramework/IJKMediaFramework.h>
  8. #import <IJKMediaFramework/IJKMediaPlayer.h>
  9. #import <AVFoundation/AVFoundation.h>
  10. #import <libkern/OSAtomic.h>
  11. @interface CoolFlutterIJK () <FlutterTexture, KKIjkNotifyDelegate>
  12. @end
  13. @implementation CoolFlutterIJK {
  14. int64_t textureId;
  15. CADisplayLink *displayLink;
  16. NSObject <FlutterTextureRegistry> *textures;
  17. IJKFFMoviePlayerController *controller;
  18. CVPixelBufferRef latestPixelBuffer;
  19. FlutterMethodChannel *channel;
  20. CoolIjkNotifyChannel *notifyChannel;
  21. int degree;
  22. }
  23. - (instancetype)initWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar {
  24. self = [super init];
  25. if (self) {
  26. self.registrar = registrar;
  27. textures = [self.registrar textures];
  28. textureId = [textures registerTexture:self];
  29. NSString *channelName = [NSString stringWithFormat:@"top.kikt/ijkplayer/%lli", textureId];
  30. channel = [FlutterMethodChannel methodChannelWithName:channelName binaryMessenger:[registrar messenger]];
  31. [channel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
  32. [self handleMethodCall:call result:result];
  33. }];
  34. }
  35. return self;
  36. }
  37. - (void)dispose {
  38. [notifyChannel dispose];
  39. [[self.registrar textures] unregisterTexture:self.id];
  40. [controller stop];
  41. [controller shutdown];
  42. controller = nil;
  43. displayLink.paused = YES;
  44. [displayLink invalidate];
  45. }
  46. - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
  47. if ([@"play" isEqualToString:call.method]) {
  48. [self play];
  49. result(@(YES));
  50. } else if ([@"pause" isEqualToString:call.method]) {
  51. [self pause];
  52. result(@(YES));
  53. } else if ([@"stop" isEqualToString:call.method]) {
  54. [self stop];
  55. result(@(YES));
  56. } else if ([@"setNetworkDataSource" isEqualToString:call.method]) {
  57. @try {
  58. NSDictionary *params = call.arguments;
  59. NSString *uri = params[@"uri"];
  60. [self setDataSourceWithUri:uri];
  61. result(@(YES));
  62. }
  63. @catch (NSException *exception) {
  64. NSLog(@"Exception occurred: %@, %@", exception, [exception userInfo]);
  65. result([FlutterError errorWithCode:@"1" message:@"设置失败" details:nil]);
  66. }
  67. } else if ([@"setAssetDataSource" isEqualToString:call.method]) {
  68. @try {
  69. NSDictionary *params = [call arguments];
  70. NSString *name = params[@"name"];
  71. NSString *pkg = params[@"package"];
  72. IJKFFMoviePlayerController *playerController = [self createControllerWithAssetName:name pkg:pkg];
  73. [self setDataSourceWithController:playerController];
  74. result(@(YES));
  75. }
  76. @catch (NSException *exception) {
  77. NSLog(@"Exception occurred: %@, %@", exception, [exception userInfo]);
  78. result([FlutterError errorWithCode:@"1" message:@"设置失败" details:nil]);
  79. }
  80. } else if ([@"setFileDataSource" isEqualToString:call.method]) {
  81. NSDictionary *params = call.arguments;
  82. NSString *path = params[@"path"];
  83. IJKFFMoviePlayerController *playerController = [self createControllerWithPath:path];
  84. [self setDataSourceWithController:playerController];
  85. result(@(YES));
  86. } else if ([@"seekTo" isEqualToString:call.method]) {
  87. NSDictionary *params = call.arguments;
  88. double target = [params[@"target"] doubleValue];
  89. [self seekTo:target];
  90. result(@(YES));
  91. } else if ([@"getInfo" isEqualToString:call.method]) {
  92. CoolVideoInfo *info = [self getInfo];
  93. result([info toMap]);
  94. } else if ([@"setVolume" isEqualToString:call.method]) {
  95. NSDictionary *params = [self params:call];
  96. float v = [params[@"volume"] floatValue] / 100;
  97. controller.playbackVolume = v;
  98. result(@(YES));
  99. } else {
  100. result(FlutterMethodNotImplemented);
  101. }
  102. }
  103. - (NSDictionary *)params:(FlutterMethodCall *)call {
  104. return call.arguments;
  105. }
  106. + (instancetype)ijkWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar {
  107. return [[self alloc] initWithRegistrar:registrar];
  108. }
  109. - (int64_t)id {
  110. return textureId;
  111. }
  112. - (void)play {
  113. [controller play];
  114. if (displayLink) {
  115. displayLink.paused = NO;
  116. }
  117. }
  118. - (void)pause {
  119. [controller pause];
  120. if (displayLink) {
  121. displayLink.paused = YES;
  122. }
  123. }
  124. - (void)stop {
  125. [controller stop];
  126. if (displayLink) {
  127. displayLink.paused = NO;
  128. }
  129. }
  130. - (void)setDataSourceWithController:(IJKFFMoviePlayerController *)ctl {
  131. if (ctl) {
  132. controller = ctl;
  133. [self prepare];
  134. }
  135. }
  136. - (IJKFFOptions *)createOption {
  137. IJKFFOptions *options = [IJKFFOptions optionsByDefault];
  138. return options;
  139. }
  140. - (void)setDataSourceWithUri:(NSString *)uri {
  141. IJKFFOptions *options = [self createOption];
  142. controller = [[IJKFFMoviePlayerController alloc] initWithContentURLString:uri withOptions:options];
  143. [self prepare];
  144. }
  145. - (void)setDegree:(int)d {
  146. degree = d;
  147. }
  148. - (void)prepare {
  149. [controller prepareToPlay];
  150. if (displayLink) {
  151. displayLink.paused = YES;
  152. [displayLink invalidate];
  153. displayLink = nil;
  154. }
  155. displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)];
  156. [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
  157. displayLink.paused = YES;
  158. notifyChannel = [CoolIjkNotifyChannel channelWithController:controller textureId:textureId registrar:self.registrar];
  159. notifyChannel.infoDelegate = self;
  160. }
  161. - (IJKFFMoviePlayerController *)createControllerWithAssetName:(NSString *)assetName pkg:(NSString *)pkg {
  162. NSString *asset;
  163. if (!pkg) {
  164. asset = [self.registrar lookupKeyForAsset:assetName];
  165. } else {
  166. asset = [self.registrar lookupKeyForAsset:assetName fromPackage:pkg];
  167. }
  168. NSString *path = [[NSBundle mainBundle] pathForResource:asset ofType:nil];
  169. NSURL *url = [NSURL fileURLWithPath:path];
  170. IJKFFOptions *options = [self createOption];
  171. return [[IJKFFMoviePlayerController alloc] initWithContentURL:url withOptions:options];
  172. }
  173. - (IJKFFMoviePlayerController *)createControllerWithPath:(NSString *)path {
  174. NSURL *url = [NSURL fileURLWithPath:path];
  175. IJKFFOptions *options = [self createOption];
  176. return [[IJKFFMoviePlayerController alloc] initWithContentURL:url withOptions:options];
  177. }
  178. - (void)seekTo:(double)target {
  179. [controller setCurrentPlaybackTime:target];
  180. }
  181. - (void)onDisplayLink:(CADisplayLink *)link {
  182. [textures textureFrameAvailable:textureId];
  183. }
  184. - (CVPixelBufferRef _Nullable)copyPixelBuffer {
  185. CVPixelBufferRef newBuffer = [controller framePixelbuffer];
  186. if (newBuffer) {
  187. CFRetain(newBuffer);
  188. CVPixelBufferRef pixelBuffer = latestPixelBuffer;
  189. while (!OSAtomicCompareAndSwapPtrBarrier(pixelBuffer, newBuffer, (void **) &latestPixelBuffer)) {
  190. pixelBuffer = latestPixelBuffer;
  191. }
  192. return pixelBuffer;
  193. }
  194. return NULL;
  195. }
  196. - (CoolVideoInfo *)getInfo {
  197. CoolVideoInfo *info = [CoolVideoInfo new];
  198. CGSize size = [controller naturalSize];
  199. NSTimeInterval duration = [controller duration];
  200. NSTimeInterval currentPlaybackTime = [controller currentPlaybackTime];
  201. info.size = size;
  202. info.duration = duration;
  203. info.currentPosition = currentPlaybackTime;
  204. info.isPlaying = [controller isPlaying];
  205. info.degree = degree;
  206. return info;
  207. }
  208. - (NSUInteger)degreeFromVideoFileWithURL:(NSURL *)url {
  209. NSUInteger mDegree = 0;
  210. AVAsset *asset = [AVAsset assetWithURL:url];
  211. NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
  212. if ([tracks count] > 0) {
  213. AVAssetTrack *videoTrack = tracks[0];
  214. CGAffineTransform t = videoTrack.preferredTransform;
  215. if (t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0) {
  216. // Portrait
  217. mDegree = 90;
  218. } else if (t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0) {
  219. // PortraitUpsideDown
  220. mDegree = 270;
  221. } else if (t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0) {
  222. // LandscapeRight
  223. mDegree = 0;
  224. } else if (t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0) {
  225. // LandscapeLeft
  226. mDegree = 180;
  227. }
  228. }
  229. return mDegree;
  230. }
  231. @end