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

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

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

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

Avatar for Kentaro Kawakami

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 ಠࣗͷϑΥʔϚοτ