FlutterIJK.m 6.9 KB

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