FlutterIJK.m 6.4 KB

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