FlutterIJK.m 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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. } else if ([@"pause" isEqualToString:call.method]) {
  49. [self pause];
  50. } else if ([@"stop" isEqualToString:call.method]) {
  51. [self stop];
  52. } else if ([@"setNetworkDataSource" isEqualToString:call.method]) {
  53. @try {
  54. NSDictionary *params = call.arguments;
  55. NSString *uri = params[@"uri"];
  56. [self setDataSourceWithUri:uri];
  57. result(nil);
  58. }
  59. @catch (NSException *exception) {
  60. NSLog(@"Exception occurred: %@, %@", exception, [exception userInfo]);
  61. result([FlutterError errorWithCode:@"1" message:@"设置失败" details:nil]);
  62. }
  63. } else if ([@"setAssetDataSource" isEqualToString:call.method]) {
  64. @try {
  65. NSDictionary *params = [call arguments];
  66. NSString *name = params[@"name"];
  67. NSString *pkg = params[@"package"];
  68. IJKFFMoviePlayerController *playerController = [self createControllerWithAssetName:name pkg:pkg];
  69. [self setDataSourceWithController:playerController];
  70. result(nil);
  71. }
  72. @catch (NSException *exception) {
  73. NSLog(@"Exception occurred: %@, %@", exception, [exception userInfo]);
  74. result([FlutterError errorWithCode:@"1" message:@"设置失败" details:nil]);
  75. }
  76. } else if ([@"setFileDataSource" isEqualToString:call.method]) {
  77. NSDictionary *params = call.arguments;
  78. NSString *path = params[@"path"];
  79. IJKFFMoviePlayerController *playerController = [self createControllerWithPath:path];
  80. } else if ([@"seekTo" isEqualToString:call.method]) {
  81. NSDictionary *params = call.arguments;
  82. double target = [params[@"target"] doubleValue];
  83. [self seekTo:target];
  84. } else if ([@"getInfo" isEqualToString:call.method]) {
  85. KKVideoInfo *info = [self getInfo];
  86. result([info toMap]);
  87. } else {
  88. result(FlutterMethodNotImplemented);
  89. }
  90. }
  91. + (instancetype)ijkWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar {
  92. return [[self alloc] initWithRegistrar:registrar];
  93. }
  94. - (int64_t)id {
  95. return textureId;
  96. }
  97. - (void)play {
  98. [controller play];
  99. }
  100. - (void)pause {
  101. [controller pause];
  102. }
  103. - (void)stop {
  104. [controller stop];
  105. }
  106. - (void)setDataSourceWithController:(IJKFFMoviePlayerController *)ctl {
  107. if (ctl) {
  108. controller = ctl;
  109. [self prepare];
  110. }
  111. }
  112. - (IJKFFOptions *)createOption {
  113. IJKFFOptions *options = [IJKFFOptions optionsByDefault];
  114. return options;
  115. }
  116. - (void)setDataSourceWithUri:(NSString *)uri {
  117. IJKFFOptions *options = [self createOption];
  118. controller = [[IJKFFMoviePlayerController alloc] initWithContentURLString:uri withOptions:options];
  119. [self prepare];
  120. }
  121. - (void)prepare {
  122. [controller prepareToPlay];
  123. if (displayLink) {
  124. displayLink.paused = YES;
  125. [displayLink invalidate];
  126. displayLink = nil;
  127. }
  128. displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)];
  129. [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
  130. displayLink.paused = YES;
  131. notifyChannel = [KKIjkNotifyChannel channelWithController:controller textureId:textureId registrar:self.registrar];
  132. notifyChannel.infoDelegate = self;
  133. }
  134. - (IJKFFMoviePlayerController *)createControllerWithAssetName:(NSString *)assetName pkg:(NSString *)pkg {
  135. NSString *asset;
  136. if (!pkg) {
  137. asset = [self.registrar lookupKeyForAsset:assetName];
  138. } else {
  139. asset = [self.registrar lookupKeyForAsset:assetName fromPackage:pkg];
  140. }
  141. NSString *path = [[NSBundle mainBundle] pathForResource:asset ofType:nil];
  142. NSURL *url = [NSURL fileURLWithPath:path];
  143. IJKFFOptions *options = [self createOption];
  144. return [[IJKFFMoviePlayerController alloc] initWithContentURL:url withOptions:options];
  145. }
  146. - (IJKFFMoviePlayerController *)createControllerWithPath:(NSString *)path {
  147. NSURL *url = [NSURL fileURLWithPath:path];
  148. IJKFFOptions *options = [self createOption];
  149. return [[IJKFFMoviePlayerController alloc] initWithContentURL:url withOptions:options];
  150. }
  151. - (void)seekTo:(double)target {
  152. [controller setCurrentPlaybackTime:target];
  153. }
  154. - (void)onDisplayLink:(CADisplayLink *)link {
  155. [textures textureFrameAvailable:textureId];
  156. }
  157. - (CVPixelBufferRef _Nullable)copyPixelBuffer {
  158. CVPixelBufferRef newBuffer = [controller framePixelbuffer];
  159. if (newBuffer) {
  160. CFRetain(newBuffer);
  161. CVPixelBufferRef pixelBuffer = latestPixelBuffer;
  162. while (!OSAtomicCompareAndSwapPtrBarrier(pixelBuffer, newBuffer, (void **) &latestPixelBuffer)) {
  163. pixelBuffer = latestPixelBuffer;
  164. }
  165. return pixelBuffer;
  166. }
  167. return NULL;
  168. }
  169. - (KKVideoInfo *)getInfo {
  170. KKVideoInfo *info = [KKVideoInfo new];
  171. CGSize size = [controller naturalSize];
  172. NSTimeInterval duration = [controller duration];
  173. NSTimeInterval currentPlaybackTime = [controller currentPlaybackTime];
  174. info.size = size;
  175. info.duration = duration;
  176. info.currentPosition = currentPlaybackTime;
  177. info.isPlaying = [controller isPlaying];
  178. return info;
  179. }
  180. @end