flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond

Home Page:https://flutter.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

iOS video_player sample doesn't show video in the emulator

nkleenest opened this issue · comments

Steps to Reproduce

I'm trying to use flutter with a FlutterTexture in the iOS emulator and I'm repeatedly hitting:

[VERBOSE-1:ios_external_texture_gl.mm(37)] Failed to create GLES texture cache: -6661

I downloaded this sample:

https://github.com/flutter/plugins/tree/master/packages/video_player

and hit the play button. This also repeatedly shows this error and doesn't render video.

Logs

Launching lib/main.dart on iPhone X in debug mode...
Running Xcode build...
Syncing files to device iPhone X...
[VERBOSE-1:ios_external_texture_gl.mm(37)] Failed to create GLES texture cache: -6661
[VERBOSE-1:ios_external_texture_gl.mm(37)] Failed to create GLES texture cache: -6661
[VERBOSE-1:ios_external_texture_gl.mm(37)] Failed to create GLES texture cache: -6661
...

Flutter Doctor

[✓] Flutter (on Mac OS X 10.13.2 17C205, locale en-US, channel dev)
    • Flutter version 0.0.25-pre.5 at [redacted]
    • Framework revision 4ae1b5f415 (5 days ago), 2018-02-07 15:18:04 -0800
    • Engine revision 9bc2efdf47
    • Tools Dart version 2.0.0-dev.19.0
    • Engine Dart version 2.0.0-edge.ea91bc9888184d5a2fc309c36656fdd325ef503c

[✓] Android toolchain - develop for Android devices (Android SDK 26.0.2)
    • Android SDK at [redacted]
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-26, build-tools 26.0.2
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-915-b08)

[✓] iOS toolchain - develop for iOS devices (Xcode 9.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 9.2, Build version 9C40b
    • ios-deploy 1.9.2
    • CocoaPods version 1.4.0

[✓] Android Studio (version 3.0)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-915-b08)

[✓] IntelliJ IDEA Community Edition (version 2017.3.4)
    • Flutter plugin version 21.2.3
    • Dart plugin version 173.4548.30

[✓] Connected devices
    • iPhone X • 0094171F-87B1-4C62-8DC5-8AE28FC5800A • ios • iOS 11.2 (simulator)

• No issues found!

The iOS emulator uses the software renderer which does not support external texture sources. You will have to use a device to test video support.

@mravn-google: If the simulators support the necessary Core Video frameworks, we can use emulated OpenGL on the simulator to enable users to test video and external texture sources on the simulator.

The culprit on Simulator appears to be our use of the texture cache. We have not had time to look into alternatives yet, but https://stackoverflow.com/questions/12813442/cvopenglestexturecache-vs-gltexsubimage2d-on-ios may provide a starting point.

So it is not as straightforward as just flipping the renderer backend on the simulators back to OpenGL then. Maybe we should log a clearer message that states that external texture sources are not available and suggests the user test on a device then (till we figure out a workaround).

At the very least, the README should warn users that iOS simulator is not supported.

Also for us poor package developers, please put a comment in TextureRegistry to the same effect ;)

commented

This cost me quite a few hours. Please, please update the documentation.

I added a note to the README.

#13331 is the equivalent issue for Android. I guess it makes sense to keep them both open because they are probably caused by different underlying issues.

commented

Hi, this is becomming a deal breaker to our dev cycle/pace.
Are there anyone looking into this?
I'm not familiar enough with flutter to do it my self, yet.

So, os there an ETA?

Thanks.

@chinmaygarde are there plans to do something or is this just not technically feasible?

Just be curious, any plan to make the video work on iOS Simulator guys?

What kind of work would be necessary to get this work? I'm willing to send in a PR (this is something that would be very beneficial IMO), but from reading this conversation, I'm not 100% sure how to alleviate the underlying problem.

It'd be very good to have this feature as I don't have neither a macbook or iPhone. I'd like to develop in a hackintosh

I have erro every time I tring to run in my device
flutter: The following NoSuchMethodError was thrown while handling a gesture:
flutter: The getter '_duration' was called on null.
flutter: Receiver: null
flutter: Tried calling: _duration
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
flutter: #1 Duration.>= (dart:core/duration.dart:175:63)
flutter: #2 _CupertinoControlsState._playPause (package:chewie/src/cupertino_controls.dart:498:45)
flutter: #3 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
flutter: #4 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:486:11)
flutter: #5 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:264:5)
flutter: #6 BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:236:7)
flutter: #7 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:156:27)
flutter: #8 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:222:20)
flutter: #9 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:198:22)
flutter: #10 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
flutter: #11 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)
flutter: #12 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)
flutter: #16 _invoke1 (dart:ui/hooks.dart:273:10)
flutter: #17 _dispatchPointerDataPacket (dart:ui/hooks.dart:182:5)
flutter: (elided 3 frames from package dart:async)
flutter:
flutter: Handler: "onTap"
flutter: Recognizer:
flutter: TapGestureRecognizer#33f47
flutter: ═════════════════════════

#43028 would allow this

#43028 would allow this

Not really. Last time I checked, CoreMedia would not vend pixel buffers on the simulator. That issue is necessary but not sufficient for video playback on the simulators. I haven't tested with Metal however.

Initial observations suggest that this issue will be fixed by using Metal rendering on iOS simulators. Unlike OpenGL, Metal uses host passthrough on simulators so the CoreVideo with OpenGL restriction should not exist when using that backend.

@chinmaygarde this is worse as I use macOS on a VM in Ubuntu. I guess Metal wont work...
:c

I expect there will be a fallback to software rendering (the current status quo) as even Metal on iOS simulators will only be available from Catalina onwards. So I wouldn't expect any regressions to your workflow. However, folks on macOS Catalina and above should see performance improvements and plugins that use external texture composition to work in simulators.

Just saying " it's because of texture renderer/cache" is massively lazy and does not show much confidence and support for professional developers.
I've never - ever - seen a framework where their simple player integration does not work in the simulator. ExoPlayer and friends clearly do work correctly in the simulator. So it's an issue with Flutter and their architecture. And I'm hitting such badly designed limitations more and more and more.
As this issue is, like many others that can be simply deal breaking, open for over two years now.. why would any professional company keep using Flutter? It's an incredible business risk with such bugs like this.
It also does not seem to be easily fixable, or a pr possible.

There are also more issues on debugging. E.g. the video player is not getting disposed, so often (even after full reload) you have to rebuild the entire app to get rid of the video player played in background for no reason.

It's also quite infuriating that such known limitations are not documented. It is not fun to waste multiple working hours trying to fix something on the devs end which is not fixable.

code sample
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: public_member_api_docs

/// An example of using the plugin, controlling lifecycle and playback of the
/// video.

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

void main() {
  runApp(
    MaterialApp(
      home: _App(),
    ),
  );
}

class _App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 3,
      child: Scaffold(
        key: const ValueKey<String>('home_page'),
        appBar: AppBar(
          title: const Text('Video player example'),
          actions: <Widget>[
            IconButton(
              key: const ValueKey<String>('push_tab'),
              icon: const Icon(Icons.navigation),
              onPressed: () {
                Navigator.push<_PlayerVideoAndPopPage>(
                  context,
                  MaterialPageRoute<_PlayerVideoAndPopPage>(
                    builder: (BuildContext context) => _PlayerVideoAndPopPage(),
                  ),
                );
              },
            )
          ],
          bottom: const TabBar(
            isScrollable: true,
            tabs: <Widget>[
              Tab(
                icon: Icon(Icons.cloud),
                text: "Remote",
              ),
              Tab(icon: Icon(Icons.insert_drive_file), text: "Asset"),
              Tab(icon: Icon(Icons.list), text: "List example"),
            ],
          ),
        ),
        body: TabBarView(
          children: <Widget>[
            _BumbleBeeRemoteVideo(),
            _ButterFlyAssetVideo(),
            _ButterFlyAssetVideoInList(),
          ],
        ),
      ),
    );
  }
}

class _ButterFlyAssetVideoInList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
        _ExampleCard(title: "Item a"),
        _ExampleCard(title: "Item b"),
        _ExampleCard(title: "Item c"),
        _ExampleCard(title: "Item d"),
        _ExampleCard(title: "Item e"),
        _ExampleCard(title: "Item f"),
        _ExampleCard(title: "Item g"),
        Card(
            child: Column(children: <Widget>[
          Column(
            children: <Widget>[
              const ListTile(
                leading: Icon(Icons.cake),
                title: Text("Video video"),
              ),
              Stack(
                  alignment: FractionalOffset.bottomRight +
                      const FractionalOffset(-0.1, -0.1),
                  children: <Widget>[
                    _ButterFlyAssetVideo(),
                    Image.asset('assets/flutter-mark-square-64.png'),
                  ]),
            ],
          ),
        ])),
        _ExampleCard(title: "Item h"),
        _ExampleCard(title: "Item i"),
        _ExampleCard(title: "Item j"),
        _ExampleCard(title: "Item k"),
        _ExampleCard(title: "Item l"),
      ],
    );
  }
}

/// A filler card to show the video in a list of scrolling contents.
class _ExampleCard extends StatelessWidget {
  const _ExampleCard({Key key, this.title}) : super(key: key);

  final String title;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          ListTile(
            leading: const Icon(Icons.airline_seat_flat_angled),
            title: Text(title),
          ),
          ButtonBar(
            children: <Widget>[
              FlatButton(
                child: const Text('BUY TICKETS'),
                onPressed: () {
                  /* ... */
                },
              ),
              FlatButton(
                child: const Text('SELL TICKETS'),
                onPressed: () {
                  /* ... */
                },
              ),
            ],
          ),
        ],
      ),
    );
  }
}

class _ButterFlyAssetVideo extends StatefulWidget {
  @override
  _ButterFlyAssetVideoState createState() => _ButterFlyAssetVideoState();
}

class _ButterFlyAssetVideoState extends State<_ButterFlyAssetVideo> {
  VideoPlayerController _controller;

  @override
  void initState() {
    super.initState();
    _controller = VideoPlayerController.asset('assets/Butterfly-209.mp4');

    _controller.addListener(() {
      setState(() {});
    });
    _controller.setLooping(true);
    _controller.initialize().then((_) => setState(() {}));
    _controller.play();
  }

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

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        children: <Widget>[
          Container(
            padding: const EdgeInsets.only(top: 20.0),
          ),
          const Text('With assets mp4'),
          Container(
            padding: const EdgeInsets.all(20),
            child: AspectRatio(
              aspectRatio: _controller.value.aspectRatio,
              child: Stack(
                alignment: Alignment.bottomCenter,
                children: <Widget>[
                  VideoPlayer(_controller),
                  _PlayPauseOverlay(controller: _controller),
                  VideoProgressIndicator(_controller, allowScrubbing: true),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class _BumbleBeeRemoteVideo extends StatefulWidget {
  @override
  _BumbleBeeRemoteVideoState createState() => _BumbleBeeRemoteVideoState();
}

class _BumbleBeeRemoteVideoState extends State<_BumbleBeeRemoteVideo> {
  VideoPlayerController _controller;

  Future<ClosedCaptionFile> _loadCaptions() async {
    final String fileContents = await DefaultAssetBundle.of(context)
        .loadString('assets/bumble_bee_captions.srt');
    return SubRipCaptionFile(fileContents);
  }

  @override
  void initState() {
    super.initState();
    _controller = VideoPlayerController.network(
      'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
      closedCaptionFile: _loadCaptions(),
    );

    _controller.addListener(() {
      setState(() {});
    });
    _controller.setLooping(true);
    _controller.initialize();
  }

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

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        children: <Widget>[
          Container(padding: const EdgeInsets.only(top: 20.0)),
          const Text('With remote mp4'),
          Container(
            padding: const EdgeInsets.all(20),
            child: AspectRatio(
              aspectRatio: _controller.value.aspectRatio,
              child: Stack(
                alignment: Alignment.bottomCenter,
                children: <Widget>[
                  VideoPlayer(_controller),
                  ClosedCaption(text: _controller.value.caption.text),
                  _PlayPauseOverlay(controller: _controller),
                  VideoProgressIndicator(_controller, allowScrubbing: true),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class _PlayPauseOverlay extends StatelessWidget {
  const _PlayPauseOverlay({Key key, this.controller}) : super(key: key);

  final VideoPlayerController controller;

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        AnimatedSwitcher(
          duration: Duration(milliseconds: 50),
          reverseDuration: Duration(milliseconds: 200),
          child: controller.value.isPlaying
              ? SizedBox.shrink()
              : Container(
                  color: Colors.black26,
                  child: Center(
                    child: Icon(
                      Icons.play_arrow,
                      color: Colors.white,
                      size: 100.0,
                    ),
                  ),
                ),
        ),
        GestureDetector(
          onTap: () {
            controller.value.isPlaying ? controller.pause() : controller.play();
          },
        ),
      ],
    );
  }
}

class _PlayerVideoAndPopPage extends StatefulWidget {
  @override
  _PlayerVideoAndPopPageState createState() => _PlayerVideoAndPopPageState();
}

class _PlayerVideoAndPopPageState extends State<_PlayerVideoAndPopPage> {
  VideoPlayerController _videoPlayerController;
  bool startedPlaying = false;

  @override
  void initState() {
    super.initState();

    _videoPlayerController =
        VideoPlayerController.asset('assets/Butterfly-209.mp4');
    _videoPlayerController.addListener(() {
      if (startedPlaying && !_videoPlayerController.value.isPlaying) {
        Navigator.pop(context);
      }
    });
  }

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

  Future<bool> started() async {
    await _videoPlayerController.initialize();
    await _videoPlayerController.play();
    startedPlaying = true;
    return true;
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      elevation: 0,
      child: Center(
        child: FutureBuilder<bool>(
          future: started(),
          builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
            if (snapshot.data == true) {
              return AspectRatio(
                aspectRatio: _videoPlayerController.value.aspectRatio,
                child: VideoPlayer(_videoPlayerController),
              );
            } else {
              return const Text('waiting for video to load');
            }
          },
        ),
      ),
    );
  }
}
flutter doctor -v
[✓] Flutter (Channel master, 1.22.0-10.0.pre.451, on Mac OS X 10.15.7 19H2
    x86_64, locale en-GB)
    • Flutter version 1.22.0-10.0.pre.451 at
      /Users/tahatesser/Code/flutter_master
    • Framework revision 79400b2462 (46 minutes ago), 2020-10-01 09:06:46 -0400
    • Engine revision 612acf349e
    • Dart version 2.11.0 (build 2.11.0-180.0.dev)

 
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    • Android SDK at /Users/tahatesser/Code/sdk
    • Platform android-30, build-tools 30.0.2
    • ANDROID_HOME = /Users/tahatesser/Code/sdk
    • Java binary at: /Applications/Android
      Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build
      1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 12.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.0.1, Build version 12A7300
    • CocoaPods version 1.9.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.0)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 50.0.1
    • Dart plugin version 193.7547
    • Java version OpenJDK Runtime Environment (build
      1.8.0_242-release-1644-b3-6222593)

[✓] VS Code (version 1.49.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.15.0

[✓] Connected device (4 available)
    • RMX2001 (mobile) • EUYTFEUSQSRGDA6D • android-arm64  • Android 10 (API 29)
    • macOS (desktop)  • macos            • darwin-x64     • Mac OS X 10.15.7
      19H2 x86_64
    • Web Server (web) • web-server       • web-javascript • Flutter Tools
    • Chrome (web)     • chrome           • web-javascript • Google Chrome
      85.0.4183.121

• No issues found!

Fixed by #67705

maybe edit the docs that say it doesn't work in the simulator

@real1900 I think that should wait until the skia surface update goes into the stable channel. I wanted to make screen captures of video but I had to switch to build with master channel for Flutter

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.