FlutterIJK.m 5.7 KB

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