如何获得视频的实际宽高比?

15

我不想让我的视频看起来被拉伸。我正在使用Chewie Flutter包作为我的视频播放器。

我尝试使用_controller.value.size.aspectRatio,但它返回错误The getter 'aspectRatio' was called on null.

这是我从相册中获取视频的代码:

Future uploadVideoFromGallery() async {
    print("CALLED");
    Map<PermissionGroup, PermissionStatus> permissions =
        await PermissionHandler().requestPermissions(
            [PermissionGroup.storage, PermissionGroup.camera]);

    if (permissions[PermissionGroup.storage] == PermissionStatus.granted) {
      var videoFile = await ImagePicker.pickVideo(source: ImageSource.gallery);
      if (videoFile != null) {
        getVideoThumbnail(videoFile.path);
        setState(() {
          isFileImage = false;
          image = videoFile;
          _controller = VideoPlayerController.file(image);
        });

        print(videoFile.path);
      }
    } else {
      debugPrint('permission not granted');
    }
  }

这里是放置videoFile的代码:

Chewie(
                        controller: ChewieController(
                          videoPlayerController: _controller,
                          aspectRatio: _controller.value.size.aspectRatio,
                          materialProgressColors: ChewieProgressColors(
                            playedColor: Color(colorSecondary),
                            handleColor: Color(colorPrimary),
                            bufferedColor: Color(colorPrimary),
                          ),
                          placeholder: Container(
                            color: Colors.grey,
                          ),
                          autoInitialize: true,
                          looping: false,
                          errorBuilder: (context, errorMessage) {
                            return Center(
                              child: Text(
                                errorMessage,
                                style: TextStyle(color: Color(colorText)),
                              ),
                            );
                          },
                        ),
                      )

1
从我刚刚阅读的文档中得知,可能只需要使用_controller.value.aspectRatio而不是_controller.value.size.aspectRatio,因此尝试否定size数据成员。 - Max Voisard
2
这很奇怪。我尝试了 _controller.value.aspectRatio。在我从相册中选择一个视频,然后点击全屏图标,再次点击关闭全屏后,它仍然被拉伸。现在它显示实际的纵横比。 - Gentle
你能展示一下你相机拍摄的屏幕吗? - hoangquyy
我们必须等待直到它被初始化。 - Soropromo
_controller.value.aspectRatio 总是返回 1.0 作为宽高比。 - Kamlesh
6个回答

17

关于此事在GitHub上存在一个问题。

import 'package:flutter/material.dart';
import 'dart:io';
import 'package:chewie/chewie.dart';
import 'package:video_player/video_player.dart';

class MyVideoPlayer extends StatefulWidget {
  final String path;

  MyVideoPlayer({Key key, @required this.path}) : super(key: key);

  @override
  _MyVideoPlayerState createState() => new _MyVideoPlayerState();
}

class _MyVideoPlayerState extends State<MyVideoPlayer> {

  VideoPlayerController _videoPlayerController;
  ChewieController _chewieController;
  Future<void> _future;

  Future<void> initVideoPlayer() async {
    await _videoPlayerController.initialize();
    setState(() {
      print(_videoPlayerController.value.aspectRatio);
      _chewieController = ChewieController(
        videoPlayerController: _videoPlayerController,
        aspectRatio: _videoPlayerController.value.aspectRatio,
        autoPlay: false,
        looping: false,
      );
    });
  }

  @override
  void initState() {
    super.initState();
    // _controller = VideoPlayerController.network('https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4');
    _videoPlayerController = VideoPlayerController.file(File(widget.path));
    _future = initVideoPlayer();
  }

  @override
  Widget build(BuildContext context) {
    return new FutureBuilder(
      future: _future,
      builder: (context, snapshot) {
        return new Center(
          child: _videoPlayerController.value.initialized
          ? AspectRatio(
            aspectRatio: _videoPlayerController.value.aspectRatio,
            child: Chewie(
              controller: _chewieController,
            ),
          )
          : new CircularProgressIndicator(),
        );
      }
    );
  }

  @override
  void dispose() {
    _videoPlayerController.dispose();
    _chewieController.dispose();
    super.dispose();
  }
}

这是 GitHub 的网址


1
始终返回1.0作为宽高比。 - Kamlesh
这个链接可能会有所帮助: https://dev59.com/zFMH5IYBdhLWcg3wtRcg#60454576 - Yasin Ege

7
插件解决方案。

在initState中:

betterPlayerController = BetterPlayerController(
      betterPlayerConfiguration,
      betterPlayerDataSource: betterPlayerDataSource,
);

betterPlayerController.addEventsListener((BetterPlayerEvent event) {
      if (event.betterPlayerEventType == BetterPlayerEventType.initialized) {
        betterPlayerController.setOverriddenAspectRatio(
            betterPlayerController.videoPlayerController.value.aspectRatio);
        setState(() {});
      }
});

在正文中:

BetterPlayer(controller: betterPlayerController),

在BetterPlayer中非常实用 - Sikshya Maharjan
如何在BetterPlayer.network()中使用它 - Vishwesh Soni
非常非常有用,好的解决方案!!! - Priyansh jain
我只能将其与fullScreenByDefault: false配合使用才能使其正常工作,将播放器包裹在宽高比内。 - Rohaitas Tanoli
@VishweshSoni,您可以使用BetterPlayerDataSource()方法来显示您想要添加的类型,例如_betterPlayerDataSource = BetterPlayerDataSource(isNetworks?BetterPlayerDataSourceType.network:BetterPlayerDataSourceType.file,widget.video); 然后将此_betterPlayerDataSource传递给_betterPlayerController.setupDataSource(_betterPlayerDataSource); - Sagar Shende

7
如果您只是使用常规的video_player包,您可以使用以下代码显示未拉伸的视频版本:
return FittedBox(
      fit: BoxFit.cover,
      child: SizedBox(
        height: model.videoPlayerController.value.size?.height ?? 0,
        width: model.videoPlayerController.value.size?.width ?? 0,
        child: VideoPlayer(model.videoPlayerController),
      ),
    );

我还在Flutter上写了一篇关于展示来自URL的视频的文章,可以看看


适合:BoxFit.contain, - Job M

1
我只使用原始videoController的纵横比,不为Chewie的videoController设置它,这对我来说很好用。要获取纵横比,您需要确保先初始化原始videoController,并添加一个监听器,以便在它调用setState时,使用正确的纵横比视频重建您的小部件。同时,您可以显示一个Circular Progress Item,直到它被初始化。

以下是我如何使用VideoPlayer和Chewie,纵横比对我起作用:

class _VideoWidget extends StatefulWidget {

  String videoURL;

  _VideoWidget({required this.videoURL});

  @override
  _VideoWidgetState createState() => _VideoWidgetState(videoURL: videoURL);
}

class _VideoWidgetState extends State<_VideoWidget> {
  late VideoPlayerController _controller;
  late Chewie _chewie;
  late ChewieController _chewieController;
  String videoURL;

  _VideoWidgetState({required this.videoURL});


  @override
  void initState() {
    super.initState();
    _controller = VideoPlayerController.network(
      videoURL,
      videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true),
    );
    _controller.addListener(() {
      setState(() {});
    });
    _controller.setLooping(true);
    _controller.initialize();
    _chewieController = ChewieController(
      videoPlayerController: _controller,
      autoPlay: false,
      looping: false,
    );
    _chewie = Chewie(
      controller: _chewieController,
    );
    _chewieController.addListener(() {
      if (!_chewieController.isFullScreen)
        {
          SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
        }
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    _chewieController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        children: <Widget>[
          Container(padding: const EdgeInsets.only(top: 20.0)),
          Padding(padding: EdgeInsets.only(top: 20)),
          Text("Video",
              style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
          Center(
            child: Container(
              height: 300,
              padding: const EdgeInsets.all(20),
              child: _controller.value.isInitialized
                  ? AspectRatio(
                      aspectRatio: _controller.value.aspectRatio,
                      child: Chewie(
                        controller: _chewieController,
                      ),
                    )
                  : Center(
                      child: SizedBox(
                          height: 30.0,
                          width: 30.0,
                          child: CircularProgressIndicator(
                              valueColor: AlwaysStoppedAnimation(Colors.blue),
                              strokeWidth: 1.0))),
            ),
          ),
        ],
      ),
    );
    return _chewie;
  }

0
首先,请尝试将_controller.value.size.aspectRatio更改为_controller.value.aspectRatio
然后,请确保您正在使用_controller.initialize()初始化控制器。
如果仍然出现错误,请添加一个空值检查。
_controller != null
    ? // Do your code
    : Text("Controller is null")

这应该可以解决你的问题。


0

你必须等待视频播放器控制器初始化完成。在then块中,仅在_playerController.initialize()完成后将纵横比值分配给ChewieController

@override
  void initState() {
    super.initState();
    Uri videoUrl = VideoProvider.fromUri(_post.url).getVideos().first.uri;
    _playerController = VideoPlayerController.network(videoUrl.toString());
    _initializeVideoPlayerFuture = _playerController.initialize().then((_) {
      _chewieController = ChewieController(
        videoPlayerController: _playerController,
        aspectRatio: _playerController.value.aspectRatio,
        allowedScreenSleep: false,
        errorBuilder: (context, error) => Center(
            child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Icon(Icons.error),
            Text(error),
          ],
        )),
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _initializeVideoPlayerFuture,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          return AspectRatio(
            aspectRatio: _playerController.value.aspectRatio,
            child: Chewie(
              controller: _chewieController,
            ),
          );
        } else {
          return Center(child: CircularProgressIndicator());
        }
      },
    );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接