Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Flutterで動画を再生するためには

 Flutterで動画を再生するためには

Kentaro Kawakami

May 27, 2021
Tweet

More Decks by Kentaro Kawakami

Other Decks in Programming

Transcript

  1. ύοέʔδͷ঺հ • video_player • pub.dev • GitHub • fl utter͕ग़͍ͯ͠Δ

    • iOS/Android/WebʹରԠ • iOS͸Objective-CɺAndroid͸Java
  2. ϩʔΧϧϑΝΠϧɾΞηοτͷ࠶ੜ class LocalVideo extends StatefulWidget { @overrid e _LocalVideoState createState()

    => _LocalVideoState() ; } class _LocalVideoState extends State<LocalVideo> { late VideoPlayerController _controller ; @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.asset('assets/Butterfly-209.mp4') ; // _controller = VideoPlayerController.file(File('file path')) ; _controller.initialize() ; _controller.play() ; } @overrid e void dispose() { _controller.dispose() ; super.dispose() ; } @overrid e Widget build(BuildContext context) { return … VideoPlayer(_controller) ; … } }
  3. ϩʔΧϧϑΝΠϧɾΞηοτͷ࠶ੜ class LocalVideo extends StatefulWidget { @overrid e _LocalVideoState createState()

    => _LocalVideoState() ; } class _LocalVideoState extends State<LocalVideo> { late VideoPlayerController _controller ; @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.asset('assets/Butterfly-209.mp4') ; // _controller = VideoPlayerController.file(File('file path')) ; _controller.initialize() ; _controller.play() ; } @overrid e void dispose() { _controller.dispose() ; super.dispose() ; } @overrid e Widget build(BuildContext context) { return … VideoPlayer(_controller) ; … } }
  4. ϩʔΧϧϑΝΠϧɾΞηοτͷ࠶ੜ class LocalVideo extends StatefulWidget { @overrid e _LocalVideoState createState()

    => _LocalVideoState() ; } class _LocalVideoState extends State<LocalVideo> { late VideoPlayerController _controller ; @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.asset('assets/Butterfly-209.mp4') ; // _controller = VideoPlayerController.file(File('file path')) ; _controller.initialize() ; _controller.play() ; } @overrid e void dispose() { _controller.dispose() ; super.dispose() ; } @overrid e Widget build(BuildContext context) { return … VideoPlayer(_controller) ; … } }
  5. ϩʔΧϧϑΝΠϧɾΞηοτͷ࠶ੜ class LocalVideo extends StatefulWidget { @overrid e _LocalVideoState createState()

    => _LocalVideoState() ; } class _LocalVideoState extends State<LocalVideo> { late VideoPlayerController _controller ; @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.asset('assets/Butterfly-209.mp4') ; // _controller = VideoPlayerController.file(File('file path')) ; _controller.initialize() ; _controller.play() ; } @overrid e void dispose() { _controller.dispose() ; super.dispose() ; } @overrid e Widget build(BuildContext context) { return … VideoPlayer(_controller) ; … } }
  6. ϩʔΧϧϑΝΠϧɾΞηοτͷ࠶ੜ class LocalVideo extends StatefulWidget { @overrid e _LocalVideoState createState()

    => _LocalVideoState() ; } class _LocalVideoState extends State<LocalVideo> { late VideoPlayerController _controller ; @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.asset('assets/Butterfly-209.mp4') ; // _controller = VideoPlayerController.file(File('file path')) ; _controller.initialize() ; _controller.play() ; } @overrid e void dispose() { _controller.dispose() ; super.dispose() ; } @overrid e Widget build(BuildContext context) { return … VideoPlayer(_controller) ; … } }
  7. ϩʔΧϧϑΝΠϧɾΞηοτͷ࠶ੜ class LocalVideo extends StatefulWidget { @overrid e _LocalVideoState createState()

    => _LocalVideoState() ; } class _LocalVideoState extends State<LocalVideo> { late VideoPlayerController _controller ; @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.asset('assets/Butterfly-209.mp4') ; // _controller = VideoPlayerController.file(File('file path')) ; _controller.initialize() ; _controller.play() ; } @overrid e void dispose() { _controller.dispose() ; super.dispose() ; } @overrid e Widget build(BuildContext context) { return … VideoPlayer(_controller) ; … } }
  8. ϦϞʔτϑΝΠϧͷ࠶ੜ class RemoteVideo extends StatefulWidget { @overrid e _RemoteVideoState createState()

    => _RemoteVideoState() ; } class _RemoteVideoState extends State<RemoteVideo> { late VideoPlayerController _controller ; @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.network('https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4') ; _controller.initialize() ; _controller.play() ; } @overrid e void dispose() { _controller.dispose() ; super.dispose() ; } @overrid e Widget build(BuildContext context) { return … VideoPlayer(_controller) ; … } }
  9. ϦϞʔτϑΝΠϧͷ࠶ੜ class RemoteVideo extends StatefulWidget { @overrid e _RemoteVideoState createState()

    => _RemoteVideoState() ; } class _RemoteVideoState extends State<RemoteVideo> { late VideoPlayerController _controller ; @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.network('https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4') ; _controller.initialize() ; _controller.play() ; } @overrid e void dispose() { _controller.dispose() ; super.dispose() ; } @overrid e Widget build(BuildContext context) { return … VideoPlayer(_controller) ; … } }
  10. ϦϞʔτϑΝΠϧͷ࠶ੜ class RemoteVideo extends StatefulWidget { @overrid e _RemoteVideoState createState()

    => _RemoteVideoState() ; } class _RemoteVideoState extends State<RemoteVideo> { late VideoPlayerController _controller ; @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.network('https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_ts/master.m3u8') ; _controller.initialize() ; _controller.play() ; } @overrid e void dispose() { _controller.dispose() ; super.dispose() ; } @overrid e Widget build(BuildContext context) { return … VideoPlayer(_controller) ; … } }
  11. ࣈນ class RemoteVideo extends StatefulWidget { … } class _RemoteVideoState

    extends State<RemoteVideo> { late VideoPlayerController _controller ; Future<ClosedCaptionFile> _loadCaptions() async { final String fileContents = await DefaultAssetBundle.of(context).loadString('assets/bumble_bee_captions.srt') ; return SubRipCaptionFile(fileContents) ; } @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.network ( 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4' , closedCaptionFile: _loadCaptions() , ) ; _controller.initialize() ; _controller.play() ; } … @overrid e Widget build(BuildContext context) { return … Stack ( children: <Widget> [ VideoPlayer(_controller) , ClosedCaption(text: _controller.value.caption.text) , ] , ) ; … } }
  12. ࣈນ class RemoteVideo extends StatefulWidget { … } class _RemoteVideoState

    extends State<RemoteVideo> { late VideoPlayerController _controller ; Future<ClosedCaptionFile> _loadCaptions() async { final String fileContents = await DefaultAssetBundle.of(context).loadString('assets/bumble_bee_captions.srt') ; return SubRipCaptionFile(fileContents) ; } @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.network ( 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4' , closedCaptionFile: _loadCaptions() , ) ; _controller.initialize() ; _controller.play() ; } … @overrid e Widget build(BuildContext context) { return … Stack ( children: <Widget> [ VideoPlayer(_controller) , ClosedCaption(text: _controller.value.caption.text) , ] , ) ; … } }
  13. ࣈນ class RemoteVideo extends StatefulWidget { … } class _RemoteVideoState

    extends State<RemoteVideo> { late VideoPlayerController _controller ; Future<ClosedCaptionFile> _loadCaptions() async { final String fileContents = await DefaultAssetBundle.of(context).loadString('assets/bumble_bee_captions.srt') ; return SubRipCaptionFile(fileContents) ; } @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.network ( 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4' , closedCaptionFile: _loadCaptions() , ) ; _controller.initialize() ; _controller.play() ; } … @overrid e Widget build(BuildContext context) { return … Stack ( children: <Widget> [ VideoPlayer(_controller) , ClosedCaption(text: _controller.value.caption.text) , ] , ) ; … } }
  14. ࣈນ class RemoteVideo extends StatefulWidget { … } class _RemoteVideoState

    extends State<RemoteVideo> { late VideoPlayerController _controller ; Future<ClosedCaptionFile> _loadCaptions() async { final String fileContents = await DefaultAssetBundle.of(context).loadString('assets/bumble_bee_captions.srt') ; return SubRipCaptionFile(fileContents) ; } @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.network ( 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4' , closedCaptionFile: _loadCaptions() , ) ; _controller.initialize() ; _controller.play() ; } … @overrid e Widget build(BuildContext context) { return … Stack ( children: <Widget> [ VideoPlayer(_controller) , ClosedCaption(text: _controller.value.caption.text) , ] , ) ; … } }
  15. γʔΫόʔ class RemoteVideo extends StatefulWidget { … } class _RemoteVideoState

    extends State<RemoteVideo> { late VideoPlayerController _controller ; @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.network('https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4') ; _controller.initialize() ; _controller.play() ; } … @overrid e Widget build(BuildContext context) { return … Stack ( alignment: Alignment.bottomCenter , children: <Widget> [ VideoPlayer(_controller) , VideoProgressIndicator(_controller, allowScrubbing: true) , ] , ) ; … } }
  16. γʔΫόʔ class RemoteVideo extends StatefulWidget { … } class _RemoteVideoState

    extends State<RemoteVideo> { late VideoPlayerController _controller ; @overrid e void initState() { super.initState() ; _controller = VideoPlayerController.network('https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4') ; _controller.initialize() ; _controller.play() ; } … @overrid e Widget build(BuildContext context) { return … Stack ( alignment: Alignment.bottomCenter , children: <Widget> [ VideoPlayer(_controller) , VideoProgressIndicator(_controller, allowScrubbing: true) , ] , ) ; … } }
  17. ϥΠϑαΠΫϧʹ߹Θͤͯ࠶ੜʗఀࢭ class _VideoAppLifeCycleObserver extends Object with WidgetsBindingObserver { _VideoAppLifeCycleObserver(this._controller) ;

    bool _wasPlayingBeforePause = false ; final VideoPlayerController _controller ; void initialize() { WidgetsBinding.instance!.addObserver(this) ; } @overrid e void didChangeAppLifecycleState(AppLifecycleState state) { switch (state) { case AppLifecycleState.paused : _wasPlayingBeforePause = _controller.value.isPlaying ; _controller.pause() ; break ; case AppLifecycleState.resumed : if (_wasPlayingBeforePause) { _controller.play() ; } break ; default : } } void dispose() { WidgetsBinding.instance!.removeObserver(this) ; } }
  18. ϥΠϑαΠΫϧʹ߹Θͤͯ࠶ੜʗఀࢭ class _VideoAppLifeCycleObserver extends Object with WidgetsBindingObserver { _VideoAppLifeCycleObserver(this._controller) ;

    bool _wasPlayingBeforePause = false ; final VideoPlayerController _controller ; void initialize() { WidgetsBinding.instance!.addObserver(this) ; } @overrid e void didChangeAppLifecycleState(AppLifecycleState state) { switch (state) { case AppLifecycleState.paused : _wasPlayingBeforePause = _controller.value.isPlaying ; _controller.pause() ; break ; case AppLifecycleState.resumed : if (_wasPlayingBeforePause) { _controller.play() ; } break ; default : } } void dispose() { WidgetsBinding.instance!.removeObserver(this) ; } }
  19. ग़དྷͳ͍͜ͱ • ը࣭ઃఆ • ϏοτϨʔτΛઃఆͰ͖ͳ͍ • ࣈນɾ෭Ի੠ • ετϦʔϜʹ৐ͬͯΔࣈນɾԻ੠ͷऔಘɺબ୒͕Ͱ͖ͳ͍ •

    UI • ࣗ෼Ͱ࣮૷͢Δඞཁ͕͋Δ • DRM fl utter#24923 • Cookieͷઃఆ • ʢΤϥʔϋϯυϦϯάʣ
  20. ग़དྷͳ͍͜ͱ • ը࣭ઃఆ • ϏοτϨʔτΛઃఆͰ͖ͳ͍ • ࣈນɾ෭Ի੠ • ετϦʔϜʹ৐ͬͯΔࣈນɾԻ੠ͷऔಘɺબ୒͕Ͱ͖ͳ͍ •

    UI • ࣗ෼Ͱ࣮૷͢Δඞཁ͕͋Δ • DRM fl utter#24923 • Cookieͷઃఆ • ʢΤϥʔϋϯυϦϯάʣ
  21. ग़དྷͳ͍͜ͱ • ը࣭ઃఆ • ϏοτϨʔτΛઃఆͰ͖ͳ͍ • ࣈນɾ෭Ի੠ • ετϦʔϜʹ৐ͬͯΔࣈນɾԻ੠ͷऔಘɺબ୒͕Ͱ͖ͳ͍ •

    UI • ࣗ෼Ͱ࣮૷͢Δඞཁ͕͋Δ • DRM fl utter#24923 • Cookieͷઃఆ • ʢΤϥʔϋϯυϦϯάʣ
  22. ग़དྷͳ͍͜ͱ • ը࣭ઃఆ • ϏοτϨʔτΛઃఆͰ͖ͳ͍ • ࣈນɾ෭Ի੠ • ετϦʔϜʹ৐ͬͯΔࣈນɾԻ੠ͷऔಘɺબ୒͕Ͱ͖ͳ͍ •

    UI • ࣗ෼Ͱ࣮૷͢Δඞཁ͕͋Δ • DRM fl utter#24923 • Cookieͷઃఆ • ʢΤϥʔϋϯυϦϯάʣ
  23. ग़དྷͳ͍͜ͱ • ը࣭ઃఆ • ϏοτϨʔτΛઃఆͰ͖ͳ͍ • ࣈນɾ෭Ի੠ • ετϦʔϜʹ৐ͬͯΔࣈນɾԻ੠ͷऔಘɺબ୒͕Ͱ͖ͳ͍ •

    UI • ࣗ෼Ͱ࣮૷͢Δඞཁ͕͋Δ • DRM fl utter#24923 • Cookieͷઃఆ • ʢΤϥʔϋϯυϦϯάʣ
  24. ग़དྷͳ͍͜ͱ • ը࣭ઃఆ • ϏοτϨʔτΛઃఆͰ͖ͳ͍ • ࣈນɾ෭Ի੠ • ετϦʔϜʹ৐ͬͯΔࣈນɾԻ੠ͷऔಘɺબ୒͕Ͱ͖ͳ͍ •

    UI • ࣗ෼Ͱ࣮૷͢Δඞཁ͕͋Δ • DRM fl utter#24923 • Cookieͷઃఆ • ʢΤϥʔϋϯυϦϯάʣ
  25. Cookieͷઃఆ • AVURLAssetੜ੒࣌ʹcookieΛ౉͍ͨ͠৔߹ • issueɾPR͸ͪΐ͍ͪΐ͍ग़ͯΔ fl utter/plugins#2882 • react-nativeͰ͸Ϛʔδ͞Ε͍ͯΔ •

    react-native-video/react-native-video#2014 • fl utter/plugins#897 (comment) • AVURLAsset(url: url, options: [AVURLAssetHTTPCookiesKey: cookies])
  26. ग़དྷͳ͍͜ͱ • ը࣭ઃఆ • ϏοτϨʔτΛઃఆͰ͖ͳ͍ • ࣈນɾ෭Ի੠ • ετϦʔϜʹ৐ͬͯΔࣈນɾԻ੠ͷऔಘɺબ୒͕Ͱ͖ͳ͍ •

    UI • ࣗ෼Ͱ࣮૷͢Δඞཁ͕͋Δ • DRM fl utter#24923 • Cookieͷઃఆ • ʢΤϥʔϋϯυϦϯάʣ
  27. ΤϥʔϋϯυϦϯά class VideoPlayerController extends ValueNotifier<VideoPlayerValue> { … } … class

    VideoPlayerValue { … final Duration duration ; final Duration position ; final Caption caption ; final List<DurationRange> buffered ; final bool isPlaying ; final bool isLooping ; final bool isBuffering ; final double volume ; final double playbackSpeed ; final String? errorDescription ; final Size size ; final bool isInitialized ; bool get hasError => errorDescription != null ; … }
  28. ΤϥʔϋϯυϦϯά class VideoPlayerController extends ValueNotifier<VideoPlayerValue> { … } … class

    VideoPlayerValue { … final Duration duration ; final Duration position ; final Caption caption ; final List<DurationRange> buffered ; final bool isPlaying ; final bool isLooping ; final bool isBuffering ; final double volume ; final double playbackSpeed ; final String? errorDescription ; final Size size ; final bool isInitialized ; bool get hasError => errorDescription != null ; … }
  29. ΤϥʔϋϯυϦϯά class VideoPlayerController extends ValueNotifier<VideoPlayerValue> { … } … class

    VideoPlayerValue { … final Duration duration ; final Duration position ; final Caption caption ; final List<DurationRange> buffered ; final bool isPlaying ; final bool isLooping ; final bool isBuffering ; final double volume ; final double playbackSpeed ; final String? errorDescription ; final Size size ; final bool isInitialized ; bool get hasError => errorDescription != null ; … }
  30. ΤϥʔϋϯυϦϯά // iO S _eventSink([FlutterError errorWithCode:@"VideoError" message:@"Video cannot be fast-forwarded

    beyond 2.0x" details:nil]) ; _eventSink([FlutterError errorWithCode:@"VideoError" message:[@"Failed to load video: “ stringByAppendingString:[item.error localizedDescription] ] details:nil]) ; // Androi d eventSink.error("VideoError", "Video player had error " + error, null);
  31. ΤϥʔϋϯυϦϯά // iO S … AVPlayerItem* item = (AVPlayerItem*)object ;

    switch (item.status) { case AVPlayerItemStatusFailed : if (_eventSink != nil) { _eventSink([FlutterError errorWithCode:@"VideoError" message:[@"Failed to load video: " stringByAppendingString:[item.error localizedDescription] ] details:nil]) ; } break ; case AVPlayerItemStatusUnknown : break ; case AVPlayerItemStatusReadyToPlay : [item addOutput:_videoOutput] ; [self sendInitialized] ; [self updatePlayingState] ; break ; } …
  32. ΤϥʔϋϯυϦϯά // iO S … AVPlayerItem* item = (AVPlayerItem*)object ;

    switch (item.status) { case AVPlayerItemStatusFailed : if (_eventSink != nil) { _eventSink([FlutterError errorWithCode:@"VideoError" message:[@"Failed to load video: " stringByAppendingString:[item.error localizedDescription] ] details:nil]) ; } break ; case AVPlayerItemStatusUnknown : break ; case AVPlayerItemStatusReadyToPlay : [item addOutput:_videoOutput] ; [self sendInitialized] ; [self updatePlayingState] ; break ; } …
  33. ΤϥʔϋϯυϦϯά // Androi d exoPlayer.addListener ( new EventListener() { …

    @Overrid e public void onPlayerError(final ExoPlaybackException error) { setBuffering(false) ; if (eventSink != null) { eventSink.error("VideoError", "Video player had error " + error, null) ; } } }) ;
  34. ΤϥʔϋϯυϦϯά // Androi d exoPlayer.addListener ( new EventListener() { …

    @Overrid e public void onPlayerError(final ExoPlaybackException error) { setBuffering(false) ; if (eventSink != null) { eventSink.error("VideoError", "Video player had error " + error, null) ; } } }) ;
  35. EventChannel initialized completed bu ff eringStart bu ff eringUpdate bu

    ff eringEnd video_player_platform_interface video_player Stream EventChannel
  36. BasicMessageChannel Future<PositionMessage> position(TextureMessage arg) async { final Object encoded =

    arg.encode() ; const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?> ( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()) ; final Map<Object?, Object?>? replyMap = await channel.send(encoded) as Map<Object?, Object?>? ; if (replyMap == null) { throw PlatformException ( code: 'channel-error' , message: 'Unable to establish connection on channel.' , details: null , ) ; } else if (replyMap['error'] != null) { final Map<Object?, Object?> error = replyMap['error'] as Map<Object?, Object?> ; throw PlatformException ( code: error['code'] as String , message: error['message'] as String? , details: error['details'] , ) ; } else { return PositionMessage.decode(replyMap['result']!) ; } }
  37. BasicMessageChannel Future<PositionMessage> position(TextureMessage arg) async { final Object encoded =

    arg.encode() ; const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?> ( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()) ; final Map<Object?, Object?>? replyMap = await channel.send(encoded) as Map<Object?, Object?>? ; if (replyMap == null) { throw PlatformException ( code: 'channel-error' , message: 'Unable to establish connection on channel.' , details: null , ) ; } else if (replyMap['error'] != null) { final Map<Object?, Object?> error = replyMap['error'] as Map<Object?, Object?> ; throw PlatformException ( code: error['code'] as String , message: error['message'] as String? , details: error['details'] , ) ; } else { return PositionMessage.decode(replyMap['result']!) ; } } class TextureMessage { int? textureId ; Object encode() { final Map<Object?, Object?> pigeonMap = <Object?, Object?>{} ; pigeonMap['textureId'] = textureId ; return pigeonMap ; } static TextureMessage decode(Object message) { final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?> ; return TextureMessage()..textureId = pigeonMap['textureId'] as int ; } }
  38. BasicMessageChannel Future<PositionMessage> position(TextureMessage arg) async { final Object encoded =

    arg.encode() ; const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?> ( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()) ; final Map<Object?, Object?>? replyMap = await channel.send(encoded) as Map<Object?, Object?>? ; if (replyMap == null) { throw PlatformException ( code: 'channel-error' , message: 'Unable to establish connection on channel.' , details: null , ) ; } else if (replyMap['error'] != null) { final Map<Object?, Object?> error = replyMap['error'] as Map<Object?, Object?> ; throw PlatformException ( code: error['code'] as String , message: error['message'] as String? , details: error['details'] , ) ; } else { return PositionMessage.decode(replyMap['result']!) ; } } class TextureMessage { int? textureId ; Object encode() { final Map<Object?, Object?> pigeonMap = <Object?, Object?>{} ; pigeonMap['textureId'] = textureId ; return pigeonMap ; } static TextureMessage decode(Object message) { final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?> ; return TextureMessage()..textureId = pigeonMap['textureId'] as int ; } }
  39. BasicMessageChannel Future<PositionMessage> position(TextureMessage arg) async { final Object encoded =

    arg.encode() ; const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?> ( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()) ; final Map<Object?, Object?>? replyMap = await channel.send(encoded) as Map<Object?, Object?>? ; if (replyMap == null) { throw PlatformException ( code: 'channel-error' , message: 'Unable to establish connection on channel.' , details: null , ) ; } else if (replyMap['error'] != null) { final Map<Object?, Object?> error = replyMap['error'] as Map<Object?, Object?> ; throw PlatformException ( code: error['code'] as String , message: error['message'] as String? , details: error['details'] , ) ; } else { return PositionMessage.decode(replyMap['result']!) ; } } class TextureMessage { int? textureId ; Object encode() { final Map<Object?, Object?> pigeonMap = <Object?, Object?>{} ; pigeonMap['textureId'] = textureId ; return pigeonMap ; } static TextureMessage decode(Object message) { final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?> ; return TextureMessage()..textureId = pigeonMap['textureId'] as int ; } }
  40. BasicMessageChannel Future<PositionMessage> position(TextureMessage arg) async { final Object encoded =

    arg.encode() ; const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?> ( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()) ; final Map<Object?, Object?>? replyMap = await channel.send(encoded) as Map<Object?, Object?>? ; if (replyMap == null) { throw PlatformException ( code: 'channel-error' , message: 'Unable to establish connection on channel.' , details: null , ) ; } else if (replyMap['error'] != null) { final Map<Object?, Object?> error = replyMap['error'] as Map<Object?, Object?> ; throw PlatformException ( code: error['code'] as String , message: error['message'] as String? , details: error['details'] , ) ; } else { return PositionMessage.decode(replyMap['result']!) ; } } class TextureMessage { int? textureId ; Object encode() { final Map<Object?, Object?> pigeonMap = <Object?, Object?>{} ; pigeonMap['textureId'] = textureId ; return pigeonMap ; } static TextureMessage decode(Object message) { final Map<Object?, Object?> pigeonMap = message as Map<Object?, Object?> ; return TextureMessage()..textureId = pigeonMap['textureId'] as int ; } }
  41. BasicMessageChannel Future<PositionMessage> position(TextureMessage arg) async { final Object encoded =

    arg.encode() ; const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?> ( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()) ; final Map<Object?, Object?>? replyMap = await channel.send(encoded) as Map<Object?, Object?>? ; if (replyMap == null) { throw PlatformException ( code: 'channel-error' , message: 'Unable to establish connection on channel.' , details: null , ) ; } else if (replyMap['error'] != null) { final Map<Object?, Object?> error = replyMap['error'] as Map<Object?, Object?> ; throw PlatformException ( code: error['code'] as String , message: error['message'] as String? , details: error['details'] , ) ; } else { return PositionMessage.decode(replyMap['result']!) ; } }
  42. BasicMessageChannel Future<PositionMessage> position(TextureMessage arg) async { final Object encoded =

    arg.encode() ; const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?> ( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()) ; final Map<Object?, Object?>? replyMap = await channel.send(encoded) as Map<Object?, Object?>? ; if (replyMap == null) { throw PlatformException ( code: 'channel-error' , message: 'Unable to establish connection on channel.' , details: null , ) ; } else if (replyMap['error'] != null) { final Map<Object?, Object?> error = replyMap['error'] as Map<Object?, Object?> ; throw PlatformException ( code: error['code'] as String , message: error['message'] as String? , details: error['details'] , ) ; } else { return PositionMessage.decode(replyMap['result']!) ; } } Channel͸APIຖʹ࡞੒
  43. BasicMessageChannel Future<PositionMessage> position(TextureMessage arg) async { final Object encoded =

    arg.encode() ; const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?> ( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()) ; final Map<Object?, Object?>? replyMap = await channel.send(encoded) as Map<Object?, Object?>? ; if (replyMap == null) { throw PlatformException ( code: 'channel-error' , message: 'Unable to establish connection on channel.' , details: null , ) ; } else if (replyMap['error'] != null) { final Map<Object?, Object?> error = replyMap['error'] as Map<Object?, Object?> ; throw PlatformException ( code: error['code'] as String , message: error['message'] as String? , details: error['details'] , ) ; } else { return PositionMessage.decode(replyMap['result']!) ; } }
  44. BasicMessageChannel Future<PositionMessage> position(TextureMessage arg) async { final Object encoded =

    arg.encode() ; const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?> ( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()) ; final Map<Object?, Object?>? replyMap = await channel.send(encoded) as Map<Object?, Object?>? ; if (replyMap == null) { throw PlatformException ( code: 'channel-error' , message: 'Unable to establish connection on channel.' , details: null , ) ; } else if (replyMap['error'] != null) { final Map<Object?, Object?> error = replyMap['error'] as Map<Object?, Object?> ; throw PlatformException ( code: error['code'] as String , message: error['message'] as String? , details: error['details'] , ) ; } else { return PositionMessage.decode(replyMap['result']!) ; } }
  45. BasicMessageChannel Future<PositionMessage> position(TextureMessage arg) async { final Object encoded =

    arg.encode() ; const BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?> ( 'dev.flutter.pigeon.VideoPlayerApi.position', StandardMessageCodec()) ; final Map<Object?, Object?>? replyMap = await channel.send(encoded) as Map<Object?, Object?>? ; if (replyMap == null) { throw PlatformException ( code: 'channel-error' , message: 'Unable to establish connection on channel.' , details: null , ) ; } else if (replyMap['error'] != null) { final Map<Object?, Object?> error = replyMap['error'] as Map<Object?, Object?> ; throw PlatformException ( code: error['code'] as String , message: error['message'] as String? , details: error['details'] , ) ; } else { return PositionMessage.decode(replyMap['result']!) ; } }
  46. ಈըͷඳը • PlatformView • Texture Widget • https://api. fl utter.dev/

    fl utter/widgets/Texture-class.html • ϓϥοτϑΥʔϜଆ͔ΒtextureIdΛड͚औΓɺϏσΦϑϨʔϜ౸ண ࣌౳ʹࣗಈతʹόοΫΤϯυͷࢦࣔʹैͬͯ࠶ඳը͞ΕΔ • ௨ৗɺDartίʔυͷ࣮ߦ͸ؚ·Εͳ͍
  47. Dart // VideoPlayerControlle r @overrid e Widget build(BuildContext context) {

    return _textureId == VideoPlayerController.kUninitializedTextureI d ? Container( ) : _videoPlayerPlatform.buildView(_textureId) ; } // video_player_platform_interfac e @overrid e Widget buildView(int textureId) { return Texture(textureId: textureId) ; }
  48. Dart // VideoPlayerControlle r @overrid e Widget build(BuildContext context) {

    return _textureId == VideoPlayerController.kUninitializedTextureI d ? Container( ) : _videoPlayerPlatform.buildView(_textureId) ; } // video_player_platform_interfac e @overrid e Widget buildView(int textureId) { return Texture(textureId: textureId) ; }
  49. Dart // VideoPlayerControlle r @overrid e Widget build(BuildContext context) {

    return _textureId == VideoPlayerController.kUninitializedTextureI d ? Container( ) : _videoPlayerPlatform.buildView(_textureId) ; } // video_player_platform_interfac e @overrid e Widget buildView(int textureId) { return Texture(textureId: textureId) ; }
  50. iOS @protocol FlutterTexture <NSObject > /** Copy the contents of

    the texture into a `CVPixelBuffer`. */ - (CVPixelBufferRef _Nullable)copyPixelBuffer ; /** * Called when the texture is unregistered. * * Called on the raster thread. */ @optional - (void)onTextureUnregistered:(NSObject<FlutterTexture>*)texture ; @end FlutterTexture
  51. iOS @protocol FlutterTexture <NSObject > /** Copy the contents of

    the texture into a `CVPixelBuffer`. */ - (CVPixelBufferRef _Nullable)copyPixelBuffer ; /** * Called when the texture is unregistered. * * Called on the raster thread. */ @optional - (void)onTextureUnregistered:(NSObject<FlutterTexture>*)texture ; @end FlutterTexture
  52. iOS @protocol FlutterTexture <NSObject > /** Copy the contents of

    the texture into a `CVPixelBuffer`. */ - (CVPixelBufferRef _Nullable)copyPixelBuffer ; /** * Called when the texture is unregistered. * * Called on the raster thread. */ @optional - (void)onTextureUnregistered:(NSObject<FlutterTexture>*)texture ; @end FlutterTexture - (CVPixelBufferRef)copyPixelBuffer { CMTime outputItemTime = [_videoOutput itemTimeForHostTime:CACurrentMediaTime()] ; if ([_videoOutput hasNewPixelBufferForItemTime:outputItemTime]) { return [_videoOutput copyPixelBufferForItemTime:outputItemTime itemTimeForDisplay:NULL] ; } else { return NULL ; } }
  53. iOS @protocol FlutterTexture <NSObject > /** Copy the contents of

    the texture into a `CVPixelBuffer`. */ - (CVPixelBufferRef _Nullable)copyPixelBuffer ; /** * Called when the texture is unregistered. * * Called on the raster thread. */ @optional - (void)onTextureUnregistered:(NSObject<FlutterTexture>*)texture ; @end FlutterTexture - (CVPixelBufferRef)copyPixelBuffer { CMTime outputItemTime = [_videoOutput itemTimeForHostTime:CACurrentMediaTime()] ; if ([_videoOutput hasNewPixelBufferForItemTime:outputItemTime]) { return [_videoOutput copyPixelBufferForItemTime:outputItemTime itemTimeForDisplay:NULL] ; } else { return NULL ; } }
  54. iOS @protocol FlutterTexture <NSObject > /** Copy the contents of

    the texture into a `CVPixelBuffer`. */ - (CVPixelBufferRef _Nullable)copyPixelBuffer ; /** * Called when the texture is unregistered. * * Called on the raster thread. */ @optional - (void)onTextureUnregistered:(NSObject<FlutterTexture>*)texture ; @end FlutterTexture
  55. iOS @protocol FlutterTexture <NSObject > /** Copy the contents of

    the texture into a `CVPixelBuffer`. */ - (CVPixelBufferRef _Nullable)copyPixelBuffer ; /** * Called when the texture is unregistered. * * Called on the raster thread. */ @optional - (void)onTextureUnregistered:(NSObject<FlutterTexture>*)texture ; @end FlutterTexture - (void)onTextureUnregistered:(NSObject<FlutterTexture>*)texture { dispatch_async(dispatch_get_main_queue(), ^ { [self dispose] ; }) ; }
  56. iOS @protocol FlutterTextureRegistry <NSObject > /** * Registers a `FlutterTexture`

    for usage in Flutter and returns an id that can be used to reference * that texture when calling into Flutter with channels. Textures must be registered on the * platform thread. */ - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture ; /** * Notifies Flutter that the content of the previously registered texture has been updated. * * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. */ - (void)textureFrameAvailable:(int64_t)textureId ; /** * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures * must be unregistered on the the platform thread. * * @param textureId The result that was previously returned from `registerTexture:`. */ - (void)unregisterTexture:(int64_t)textureId ; @end FlutterTextureRegistry
  57. iOS @protocol FlutterTextureRegistry <NSObject > /** * Registers a `FlutterTexture`

    for usage in Flutter and returns an id that can be used to reference * that texture when calling into Flutter with channels. Textures must be registered on the * platform thread. */ - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture ; /** * Notifies Flutter that the content of the previously registered texture has been updated. * * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. */ - (void)textureFrameAvailable:(int64_t)textureId ; /** * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures * must be unregistered on the the platform thread. * * @param textureId The result that was previously returned from `registerTexture:`. */ - (void)unregisterTexture:(int64_t)textureId ; @end FlutterTextureRegistry
  58. iOS @protocol FlutterTextureRegistry <NSObject > /** * Registers a `FlutterTexture`

    for usage in Flutter and returns an id that can be used to reference * that texture when calling into Flutter with channels. Textures must be registered on the * platform thread. */ - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture ; /** * Notifies Flutter that the content of the previously registered texture has been updated. * * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. */ - (void)textureFrameAvailable:(int64_t)textureId ; /** * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures * must be unregistered on the the platform thread. * * @param textureId The result that was previously returned from `registerTexture:`. */ - (void)unregisterTexture:(int64_t)textureId ; @end FlutterTextureRegistry … int64_t textureId = [_registry registerTexture:player] ; …
  59. iOS @protocol FlutterTextureRegistry <NSObject > /** * Registers a `FlutterTexture`

    for usage in Flutter and returns an id that can be used to reference * that texture when calling into Flutter with channels. Textures must be registered on the * platform thread. */ - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture ; /** * Notifies Flutter that the content of the previously registered texture has been updated. * * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. */ - (void)textureFrameAvailable:(int64_t)textureId ; /** * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures * must be unregistered on the the platform thread. * * @param textureId The result that was previously returned from `registerTexture:`. */ - (void)unregisterTexture:(int64_t)textureId ; @end FlutterTextureRegistry … int64_t textureId = [_registry registerTexture:player] ; … textureId͕ฦΔ
  60. iOS @protocol FlutterTextureRegistry <NSObject > /** * Registers a `FlutterTexture`

    for usage in Flutter and returns an id that can be used to reference * that texture when calling into Flutter with channels. Textures must be registered on the * platform thread. */ - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture ; /** * Notifies Flutter that the content of the previously registered texture has been updated. * * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. */ - (void)textureFrameAvailable:(int64_t)textureId ; /** * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures * must be unregistered on the the platform thread. * * @param textureId The result that was previously returned from `registerTexture:`. */ - (void)unregisterTexture:(int64_t)textureId ; @end FlutterTextureRegistry
  61. iOS @protocol FlutterTextureRegistry <NSObject > /** * Registers a `FlutterTexture`

    for usage in Flutter and returns an id that can be used to reference * that texture when calling into Flutter with channels. Textures must be registered on the * platform thread. */ - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture ; /** * Notifies Flutter that the content of the previously registered texture has been updated. * * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. */ - (void)textureFrameAvailable:(int64_t)textureId ; /** * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures * must be unregistered on the the platform thread. * * @param textureId The result that was previously returned from `registerTexture:`. */ - (void)unregisterTexture:(int64_t)textureId ; @end FlutterTextureRegistry • FlutterʹTexture͕ߋ৽͞Εͨͱ఻͑Δ • FlutterTexture.copyPixcelBu ff er()͕ݺͼ͞ΕΔ
  62. iOS @protocol FlutterTextureRegistry <NSObject > /** * Registers a `FlutterTexture`

    for usage in Flutter and returns an id that can be used to reference * that texture when calling into Flutter with channels. Textures must be registered on the * platform thread. */ - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture ; /** * Notifies Flutter that the content of the previously registered texture has been updated. * * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. */ - (void)textureFrameAvailable:(int64_t)textureId ; /** * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures * must be unregistered on the the platform thread. * * @param textureId The result that was previously returned from `registerTexture:`. */ - (void)unregisterTexture:(int64_t)textureId ; @end FlutterTextureRegistry _displayLink = [CADisplayLink displayLinkWithTarget:frameUpdate r selector:@selector(onDisplayLink:)] ; . .. - (void)onDisplayLink:(CADisplayLink*)link { [_registry textureFrameAvailable:_textureId] ; }
  63. iOS @protocol FlutterTextureRegistry <NSObject > /** * Registers a `FlutterTexture`

    for usage in Flutter and returns an id that can be used to reference * that texture when calling into Flutter with channels. Textures must be registered on the * platform thread. */ - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture ; /** * Notifies Flutter that the content of the previously registered texture has been updated. * * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. */ - (void)textureFrameAvailable:(int64_t)textureId ; /** * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures * must be unregistered on the the platform thread. * * @param textureId The result that was previously returned from `registerTexture:`. */ - (void)unregisterTexture:(int64_t)textureId ; @end FlutterTextureRegistry _displayLink = [CADisplayLink displayLinkWithTarget:frameUpdate r selector:@selector(onDisplayLink:)] ; . .. - (void)onDisplayLink:(CADisplayLink*)link { [_registry textureFrameAvailable:_textureId] ; }
  64. iOS @protocol FlutterTextureRegistry <NSObject > /** * Registers a `FlutterTexture`

    for usage in Flutter and returns an id that can be used to reference * that texture when calling into Flutter with channels. Textures must be registered on the * platform thread. */ - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture ; /** * Notifies Flutter that the content of the previously registered texture has been updated. * * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. */ - (void)textureFrameAvailable:(int64_t)textureId ; /** * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures * must be unregistered on the the platform thread. * * @param textureId The result that was previously returned from `registerTexture:`. */ - (void)unregisterTexture:(int64_t)textureId ; @end FlutterTextureRegistry _displayLink = [CADisplayLink displayLinkWithTarget:frameUpdate r selector:@selector(onDisplayLink:)] ; . .. - (void)onDisplayLink:(CADisplayLink*)link { [_registry textureFrameAvailable:_textureId] ; }
  65. iOS @protocol FlutterTextureRegistry <NSObject > /** * Registers a `FlutterTexture`

    for usage in Flutter and returns an id that can be used to reference * that texture when calling into Flutter with channels. Textures must be registered on the * platform thread. */ - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture ; /** * Notifies Flutter that the content of the previously registered texture has been updated. * * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. */ - (void)textureFrameAvailable:(int64_t)textureId ; /** * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures * must be unregistered on the the platform thread. * * @param textureId The result that was previously returned from `registerTexture:`. */ - (void)unregisterTexture:(int64_t)textureId ; @end FlutterTextureRegistry
  66. iOS @protocol FlutterTextureRegistry <NSObject > /** * Registers a `FlutterTexture`

    for usage in Flutter and returns an id that can be used to reference * that texture when calling into Flutter with channels. Textures must be registered on the * platform thread. */ - (int64_t)registerTexture:(NSObject<FlutterTexture>*)texture ; /** * Notifies Flutter that the content of the previously registered texture has been updated. * * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. */ - (void)textureFrameAvailable:(int64_t)textureId ; /** * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures * must be unregistered on the the platform thread. * * @param textureId The result that was previously returned from `registerTexture:`. */ - (void)unregisterTexture:(int64_t)textureId ; @end FlutterTextureRegistry - (void)dispose:(FLTTextureMessage*)input error:(FlutterError**)error { … [_registry unregisterTexture:input.textureId.intValue];
  67. Android public interface TextureRegistry { /* * * Creates and

    registers a SurfaceTexture managed by the Flutter engine . * * @return A SurfaceTextureEntry . * / SurfaceTextureEntry createSurfaceTexture() ; /** A registry entry for a managed SurfaceTexture. * / interface SurfaceTextureEntry { /** @return The managed SurfaceTexture. * / SurfaceTexture surfaceTexture() ; /** @return The identity of this SurfaceTexture. * / long id() ; /** Deregisters and releases this SurfaceTexture. * / void release() ; } } TextureRegistry
  68. Android public interface TextureRegistry { /* * * Creates and

    registers a SurfaceTexture managed by the Flutter engine . * * @return A SurfaceTextureEntry . * / SurfaceTextureEntry createSurfaceTexture() ; /** A registry entry for a managed SurfaceTexture. * / interface SurfaceTextureEntry { /** @return The managed SurfaceTexture. * / SurfaceTexture surfaceTexture() ; /** @return The identity of this SurfaceTexture. * / long id() ; /** Deregisters and releases this SurfaceTexture. * / void release() ; } } TextureRegistry
  69. Android public interface TextureRegistry { /* * * Creates and

    registers a SurfaceTexture managed by the Flutter engine . * * @return A SurfaceTextureEntry . * / SurfaceTextureEntry createSurfaceTexture() ; /** A registry entry for a managed SurfaceTexture. * / interface SurfaceTextureEntry { /** @return The managed SurfaceTexture. * / SurfaceTexture surfaceTexture() ; /** @return The identity of this SurfaceTexture. * / long id() ; /** Deregisters and releases this SurfaceTexture. * / void release() ; } } TextureRegistry .. . TextureRegistry.SurfaceTextureEntry handle = flutterState.textureRegistry.createSurfaceTexture() ; ...
  70. Android public interface TextureRegistry { /* * * Creates and

    registers a SurfaceTexture managed by the Flutter engine . * * @return A SurfaceTextureEntry . * / SurfaceTextureEntry createSurfaceTexture() ; /** A registry entry for a managed SurfaceTexture. * / interface SurfaceTextureEntry { /** @return The managed SurfaceTexture. * / SurfaceTexture surfaceTexture() ; /** @return The identity of this SurfaceTexture. * / long id() ; /** Deregisters and releases this SurfaceTexture. * / void release() ; } } TextureRegistry
  71. Android public interface TextureRegistry { /* * * Creates and

    registers a SurfaceTexture managed by the Flutter engine . * * @return A SurfaceTextureEntry . * / SurfaceTextureEntry createSurfaceTexture() ; /** A registry entry for a managed SurfaceTexture. * / interface SurfaceTextureEntry { /** @return The managed SurfaceTexture. * / SurfaceTexture surfaceTexture() ; /** @return The identity of this SurfaceTexture. * / long id() ; /** Deregisters and releases this SurfaceTexture. * / void release() ; } } TextureRegistry ... surface = new Surface(textureEntry.surfaceTexture()) ; exoPlayer.setVideoSurface(surface) ; ...
  72. Android public interface TextureRegistry { /* * * Creates and

    registers a SurfaceTexture managed by the Flutter engine . * * @return A SurfaceTextureEntry . * / SurfaceTextureEntry createSurfaceTexture() ; /** A registry entry for a managed SurfaceTexture. * / interface SurfaceTextureEntry { /** @return The managed SurfaceTexture. * / SurfaceTexture surfaceTexture() ; /** @return The identity of this SurfaceTexture. * / long id() ; /** Deregisters and releases this SurfaceTexture. * / void release() ; } } TextureRegistry
  73. Android public interface TextureRegistry { /* * * Creates and

    registers a SurfaceTexture managed by the Flutter engine . * * @return A SurfaceTextureEntry . * / SurfaceTextureEntry createSurfaceTexture() ; /** A registry entry for a managed SurfaceTexture. * / interface SurfaceTextureEntry { /** @return The managed SurfaceTexture. * / SurfaceTexture surfaceTexture() ; /** @return The identity of this SurfaceTexture. * / long id() ; /** Deregisters and releases this SurfaceTexture. * / void release() ; } } TextureRegistry textureId͕ฦΔ
  74. pigeon/messages.dart class LimitBitrateMessage { int textureId ; int limitBitrate ;

    } .. . abstract class VideoPlayerApi { void initialize() ; TextureMessage create(CreateMessage msg) ; void dispose(TextureMessage msg) ; void setLooping(LoopingMessage msg) ; void setVolume(VolumeMessage msg) ; void setPlaybackSpeed(PlaybackSpeedMessage msg) ; void play(TextureMessage msg) ; PositionMessage position(TextureMessage msg) ; void seekTo(PositionMessage msg) ; void pause(TextureMessage msg) ; void setMixWithOthers(MixWithOthersMessage msg) ; void setLimitBitrate(LimitBitrateMessage msg) ; }
  75. pigeon/messages.dart class LimitBitrateMessage { int textureId ; int limitBitrate ;

    } .. . abstract class VideoPlayerApi { void initialize() ; TextureMessage create(CreateMessage msg) ; void dispose(TextureMessage msg) ; void setLooping(LoopingMessage msg) ; void setVolume(VolumeMessage msg) ; void setPlaybackSpeed(PlaybackSpeedMessage msg) ; void play(TextureMessage msg) ; PositionMessage position(TextureMessage msg) ; void seekTo(PositionMessage msg) ; void pause(TextureMessage msg) ; void setMixWithOthers(MixWithOthersMessage msg) ; void setLimitBitrate(LimitBitrateMessage msg) ; }
  76. pigeon/messages.dart class LimitBitrateMessage { int textureId ; int limitBitrate ;

    } .. . abstract class VideoPlayerApi { void initialize() ; TextureMessage create(CreateMessage msg) ; void dispose(TextureMessage msg) ; void setLooping(LoopingMessage msg) ; void setVolume(VolumeMessage msg) ; void setPlaybackSpeed(PlaybackSpeedMessage msg) ; void play(TextureMessage msg) ; PositionMessage position(TextureMessage msg) ; void seekTo(PositionMessage msg) ; void pause(TextureMessage msg) ; void setMixWithOthers(MixWithOthersMessage msg) ; void setLimitBitrate(LimitBitrateMessage msg) ; }
  77. ϑΝΠϧͷੜ੒ $flutter pub run pigeon --input pigeons/messages.dart —dart_null_safet y $(cd

    ../../../; ./script/incremental_build.sh format --travis --clang-format=clang-format-7)
  78. ϑΝΠϧͷੜ੒ $flutter pub run pigeon --input pigeons/messages.dart —dart_null_safet y $(cd

    ../../../; ./script/incremental_build.sh format --travis --clang-format=clang-format-7)
  79. ϑΝΠϧͷੜ੒ $flutter pub run pigeon --input pigeons/messages.dart —dart_null_safet y $(cd

    ../../../; ./script/incremental_build.sh format --travis --clang-format=clang-format-7)
  80. ϑΝΠϧͷੜ੒ $flutter pub run pigeon --input pigeons/messages.dart —dart_null_safet y $(cd

    ../../../; ./script/incremental_build.sh format --travis --clang-format=clang-format-7) fl utter/plugin ಠࣗͷϑΥʔϚοτ