Przeglądaj źródła

screen shot example api(not support).

Caijinglong 6 lat temu
rodzic
commit
2f0f6ce7f1

+ 1 - 0
TODOLIST.md

@@ -36,6 +36,7 @@
     - [ ] iPad 无效,暂不知原因
   - [x] 屏幕旋转: 这个指强制当前屏幕旋转至哪个方向
     - [ ] iPad 无效,暂不知原因
+  - [ ] 截图
 - [x] 默认控制器 UI
   - [x] 进度条
   - [x] 播放/暂停按钮

+ 12 - 0
android/src/main/java/top/kikt/ijkplayer/Ijk.kt

@@ -4,6 +4,7 @@ package top.kikt.ijkplayer
 
 
 import android.util.Base64
+import android.view.TextureView
 import io.flutter.plugin.common.MethodCall
 import io.flutter.plugin.common.MethodChannel
 import io.flutter.plugin.common.PluginRegistry
@@ -114,12 +115,23 @@ class Ijk(private val registry: PluginRegistry.Registrar) : MethodChannel.Method
 
 //                result?.success(this.mediaPlayer.setVolume())
             }
+            "screenShot" -> {
+                screenShot()
+                result?.success(byteArrayOf())
+            }
             else -> {
                 result?.notImplemented()
             }
         }
     }
 
+    private fun screenShot() {
+        val textureView = TextureView(registry.activity())
+        textureView.surfaceTexture = textureEntry.surfaceTexture()
+        val bitmap = textureView.bitmap
+        logi("bitmap width = ${bitmap?.width} height = ${bitmap?.height}")
+    }
+
     fun getInfo(): Info {
         val duration = mediaPlayer.duration
         val currentPosition = mediaPlayer.currentPosition

+ 3 - 0
example/lib/i18n/cn.dart

@@ -56,4 +56,7 @@ class _I18nZh extends I18n {
 
   @override
   String get playFinishToast => "播放完毕";
+
+  @override
+  String get screenshotTitle => "截取视频画面(开发中)";
 }

+ 3 - 0
example/lib/i18n/en.dart

@@ -55,4 +55,7 @@ class _I18nEn extends I18n {
 
   @override
   String get playFinishToast => "Play video finish";
+
+  @override
+  String get screenshotTitle => "screenshot video frame(experiment)";
 }

+ 2 - 0
example/lib/i18n/i18n.dart

@@ -40,6 +40,8 @@ abstract class I18n {
   String get useStreamUsage;
 
   String get playFinishToast;
+
+  String get screenshotTitle;
 }
 
 I18n get currentI18n => I18n(window.locale);

+ 2 - 0
example/lib/page/index.dart

@@ -7,6 +7,7 @@ import 'package:ijkplayer_example/page/full_screen.dart';
 import 'package:ijkplayer_example/page/gallery_page.dart';
 import 'package:ijkplayer_example/page/network.dart';
 import 'package:ijkplayer_example/page/paging_page.dart';
+import 'package:ijkplayer_example/page/screen_shot_page.dart';
 import 'package:ijkplayer_example/page/video_list.dart';
 
 class IndexPage extends StatefulWidget {
@@ -32,6 +33,7 @@ class _IndexPageState extends State<IndexPage> {
           buildButton(currentI18n.withDialogButton, DialogVideoPage()),
           buildButton(currentI18n.pageViewButton, PagingPickPage()),
           buildButton(currentI18n.useStreamUsage, ControllerStreamUsagePage()),
+          buildButton(currentI18n.screenshotTitle, ScreenShotPage()),
         ],
       ),
     );

+ 19 - 0
example/lib/page/paging_page.dart

@@ -131,6 +131,25 @@ class _PagingPageState extends State<PagingPage> {
     );
   }
 
+  // Hold up to three controllers.
+  // IjkMediaController initControllers(int current) {
+  //   var src = widget.dataSourceList[current];
+  //   var ctl = getControllerWithSrc(src);
+
+  //   var next = current + 1;
+  //   if (next < widget.dataSourceList.length) {
+  //     var datasource = widget.dataSourceList[next];
+  //     var nextCtl = getControllerWithSrc(datasource);
+  //   }
+
+  //   return ctl;
+  // }
+
+  // void disposeOther(int current) {
+  //   var last = current - 1;
+  //   var next = current + 1;
+  // }
+
   Widget _buildItem(BuildContext context, int index) {
     var src = widget.dataSourceList[index];
     var ctl = getControllerWithSrc(src);

+ 77 - 0
example/lib/page/screen_shot_page.dart

@@ -0,0 +1,77 @@
+import 'dart:typed_data';
+import 'dart:async';
+import 'package:flutter/material.dart';
+
+import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
+import 'package:ijkplayer_example/i18n/i18n.dart';
+import 'dart:ui' as ui;
+
+class ScreenShotPage extends StatefulWidget {
+  @override
+  _ScreenShotPageState createState() => _ScreenShotPageState();
+}
+
+class _ScreenShotPageState extends State<ScreenShotPage> {
+  IjkMediaController mediaController = IjkMediaController();
+
+  ImageProvider provider;
+
+  @override
+  void initState() {
+    super.initState();
+    mediaController.setDataSource(
+        DataSource.network(
+            "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4"),
+        autoPlay: true);
+  }
+
+  @override
+  void dispose() {
+    mediaController.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        title: Text(currentI18n.screenshotTitle),
+      ),
+      body: ListView(
+        children: <Widget>[
+          AspectRatio(
+            aspectRatio: 1280 / 720,
+            child: IjkPlayer(
+              mediaController: mediaController,
+            ),
+          ),
+          FlatButton(
+            child: Text(currentI18n.screenshotTitle),
+            onPressed: () async {
+              var uint8List = await mediaController.screenShot();
+              provider = MemoryImage(uint8List);
+              setState(() {});
+
+              var size = await getImageForUint8List(uint8List);
+              print("width = ${size.width} , height = ${size.height}");
+            },
+          ),
+          provider == null
+              ? Container()
+              : Image(
+                  image: provider,
+                ),
+        ],
+      ),
+    );
+  }
+}
+
+Future<Size> getImageForUint8List(Uint8List imageSrc) {
+  Completer<Size> completer = Completer();
+  ui.decodeImageFromList(imageSrc, (img) {
+    completer.complete(Size(img.width.toDouble(), img.height.toDouble()));
+    img.dispose();
+  });
+  return completer.future;
+}

+ 9 - 1
lib/src/controller.dart

@@ -1,7 +1,7 @@
 part of './ijkplayer.dart';
 
 /// Media Controller
-class IjkMediaController {
+class IjkMediaController with IjkMediaControllerMixin {
   /// MediaController
   IjkMediaController({
     this.autoRotate = true,
@@ -430,6 +430,14 @@ class _IjkPlugin {
       "volume": volume,
     });
   }
+
+  Future<Uint8List> screenShot() async {
+    var result = await channel.invokeMethod("screenShot");
+    if (result == null) {
+      return null;
+    }
+    return result;
+  }
 }
 
 /// Entity classe for data sources.

+ 55 - 4
lib/src/ijkplayer.dart

@@ -1,8 +1,10 @@
 import 'dart:async';
 import 'dart:io';
+import 'dart:typed_data';
 
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
+import 'package:flutter_ijkplayer/src/ijkplayer_controller_mixin.dart';
 
 import 'error.dart';
 import 'package:flutter_ijkplayer/src/helper/logutil.dart';
@@ -41,7 +43,7 @@ class IjkPlayer extends StatefulWidget {
 class IjkPlayerState extends State<IjkPlayer> {
   /// see [IjkMediaController]
   IjkMediaController controller;
-
+  GlobalKey _wrapperKey = GlobalKey();
   @override
   void initState() {
     super.initState();
@@ -92,7 +94,12 @@ class IjkPlayerState extends State<IjkPlayer> {
 
   Widget _buildTexture(int id, VideoInfo info) {
     if (widget?.textureBuilder != null) {
-      return widget.textureBuilder.call(context, controller, info);
+      var texture = widget.textureBuilder.call(context, controller, info);
+      return _IjkPlayerWrapper(
+        child: texture,
+        globalKey: _wrapperKey,
+        controller: controller,
+      );
     }
 
     if (id == null) {
@@ -103,9 +110,53 @@ class IjkPlayerState extends State<IjkPlayer> {
 
     return Container(
       color: Colors.black,
-      child: Texture(
-        textureId: id,
+      child: _IjkPlayerWrapper(
+        globalKey: _wrapperKey,
+        controller: controller,
+        child: Texture(
+          textureId: id,
+        ),
       ),
     );
   }
 }
+
+class _IjkPlayerWrapper extends StatefulWidget {
+  final Widget child;
+  final GlobalKey globalKey;
+  final IjkMediaController controller;
+
+  const _IjkPlayerWrapper({
+    @required this.globalKey,
+    @required this.child,
+    Key key,
+    @required this.controller,
+  }) : super(key: key);
+
+  @override
+  __IjkPlayerWrapperState createState() => __IjkPlayerWrapperState();
+}
+
+class __IjkPlayerWrapperState extends State<_IjkPlayerWrapper> {
+  @override
+  void initState() {
+    super.initState();
+    widget.controller?.attach(widget.globalKey);
+    print("wrapper state init ");
+  }
+
+  @override
+  void dispose() {
+    widget.controller?.detach(widget.globalKey);
+    print("wrapper state dispose");
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return RepaintBoundary(
+      child: widget.child,
+      key: widget.globalKey,
+    );
+  }
+}

+ 33 - 0
lib/src/ijkplayer_controller_mixin.dart

@@ -0,0 +1,33 @@
+import 'dart:typed_data';
+import 'dart:ui' as ui;
+import 'package:flutter/material.dart';
+import 'package:flutter/rendering.dart';
+
+mixin IjkMediaControllerMixin {
+  List<GlobalKey> _keys = [];
+
+  attach(GlobalKey key) {
+    print("IjkMediaControllerMixin attach $key");
+    _keys.add(key);
+  }
+
+  detach(GlobalKey key) {
+    print("IjkMediaControllerMixin detach $key");
+    _keys.remove(key);
+  }
+
+  Future<Uint8List> screenShot() async {
+    print("IjkMediaControllerMixin will screen shot");
+    if (_keys.isEmpty) {
+      print("IjkMediaControllerMixin screen shot key is empty = $_keys");
+      return null;
+    }
+    var key = _keys[0];
+    RenderRepaintBoundary boundary = key.currentContext.findRenderObject();
+    var image = await boundary.toImage();
+    print(
+        "IjkMediaControllerMixin screen shot image width = ${image.width} , height = ${image.height}");
+    var byteData = await image.toByteData(format: ui.ImageByteFormat.png);
+    return byteData.buffer.asUint8List();
+  }
+}

+ 1 - 4
lib/src/widget/ijkplayer_builder.dart

@@ -56,10 +56,7 @@ class DefaultIJKPlayerWrapper extends StatelessWidget {
     );
 
     if (!controller.autoRotate) {
-      return AspectRatio(
-        aspectRatio: null,
-        child: w,
-      );
+      return w;
     }
 
     int degree = info?.degree ?? 0;