jhomlala / betterplayer

Better video player for Flutter, with multiple configuration options. Solving typical use cases!
Apache License 2.0
919 stars 980 forks source link

[BUG] Video source error on Cached videos for Android API old versions (<7.0) #851

Open SalahAdDin opened 2 years ago

SalahAdDin commented 2 years ago

History check I checked all issues and i couldn't fine anything related this issue.

Describe the bug We created a widget to handle all videos on our application with a cache by default; we tested it on latest Android versions and it does no show any problem, but when we test it on old Android version, we get Video player had error com.google.android.exoplayer2.ExoPlaybackException: Source error.

We know it is related to cache cause if we remove the cache configuration, we have no any error.

To Reproduce Steps to reproduce the behavior:

  1. Run the application on a old android version.
  2. Play the video.
  3. See error.

*Example code cached_network_video.dart

import 'package:better_player/better_player.dart';
import 'package:flutter/material.dart';

///
class CachedNetworkVideo extends StatefulWidget {
  ///
  const CachedNetworkVideo({
    Key? key,
    required this.dataSource,
    this.autoPlay = false,
    this.looping = false,
    this.enableControls = false,
    this.onFinished,
  }) : super(key: key);

  ///
  final String dataSource;

  ///
  final bool looping;

  ///
  final bool autoPlay;

  /// Set controls always visible (controls won't fade out, will be always over video).
  final bool enableControls;

  /// A [Function] to call once the video is finished.
  final Function? onFinished;

  @override
  _CachedNetworkVideoState createState() => _CachedNetworkVideoState();
}

class _CachedNetworkVideoState extends State<CachedNetworkVideo> {
  late BetterPlayerController _betterPlayerController;
  late BetterPlayerDataSource _betterPlayerDataSource;

  @override
  void initState() {
    const BetterPlayerControlsConfiguration betterPlayerControlsConfiguration =
        BetterPlayerControlsConfiguration(
      enableOverflowMenu: false,
      showControlsOnInitialize: false,
      backgroundColor: Colors.transparent,
    );
    final BetterPlayerConfiguration betterPlayerConfiguration =
        BetterPlayerConfiguration(
      aspectRatio: 16 / 9,
      fit: BoxFit.contain,
      autoPlay: widget.autoPlay,
      looping: widget.looping,
      controlsConfiguration: betterPlayerControlsConfiguration,
      errorBuilder: (BuildContext context, String? errorMessage) {
        return Center(
          child: Text(
            errorMessage ?? "Oops!",
            style: const TextStyle(color: Colors.white),
          ),
        );
      },
    );

    _betterPlayerDataSource = BetterPlayerDataSource(
      BetterPlayerDataSourceType.network,
      widget.dataSource,
      cacheConfiguration: const BetterPlayerCacheConfiguration(
        useCache: true,
        preCacheSize: 10 * 1024 * 1024,

        ///Android only option to use cached video between app sessions
        key: "testCacheKey",
      ),
    );

    _betterPlayerController = BetterPlayerController(betterPlayerConfiguration)
      ..setControlsEnabled(widget.enableControls);
    _betterPlayerController.setupDataSource(_betterPlayerDataSource);
    // ignore: cascade_invocations
    _betterPlayerController.addEventsListener((BetterPlayerEvent event) {
      if (event.betterPlayerEventType == BetterPlayerEventType.finished &&
          widget.onFinished != null) {
        widget.onFinished?.call();
      }
    });

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return AspectRatio(
      aspectRatio: 16 / 9,
      child: BetterPlayer(controller: _betterPlayerController),
    );
  }
}

main:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:introduction_screen/introduction_screen.dart';

void main() => runApp(App());

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(
      SystemUiOverlayStyle.dark.copyWith(statusBarColor: Colors.transparent),
    );

    return MaterialApp(
      title: 'Introduction screen',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primarySwatch: Colors.blue),
      home: OnBoardingPage(),
    );
  }
}

class OnBoardingPage extends StatefulWidget {
  @override
  _OnBoardingPageState createState() => _OnBoardingPageState();
}

class _OnBoardingPageState extends State<OnBoardingPage> {
  final introKey = GlobalKey<IntroductionScreenState>();

  void _onIntroEnd(context) {
    Navigator.of(context).push(
      MaterialPageRoute(builder: (_) => HomePage()),
    );
  }
  @override
  Widget build(BuildContext context) {

    return IntroductionScreen(
        pages: <PageViewModel>[
          PageViewModel(
            title: "",
            image: Center(
              child: CachedNetworkVideo(
                dataSource: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
                autoPlay: true,
              ),
            ),
            body: "",
            decoration: const PageDecoration(fullScreen: true),
          ),
        ],
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: const Center(child: Text("This is the screen after Introduction")),
    );
  }
}

Expected behavior It should show the video as normal it does on superior android versions.

Screenshots image

Flutter doctor

❯ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.5.3, on macOS 12.0.1 21A559 darwin-x64, locale en-TR)
[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
[✓] Xcode - develop for iOS and macOS
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] VS Code (version 1.63.0)
[✓] Connected device (2 available)

• No issues found!

Better Player version

Smartphone (please complete the following information):

Additional context It happens on versions earlier to Android 7.0(API 24).

jhomlala commented 2 years ago

@SalahAdDin Can you provide error log?

SalahAdDin commented 2 years ago

@SalahAdDin Can you provide error log?

[ +137 ms] I/ExoPlayerImpl( 5641): Init 8cc2ca5 [ExoPlayerLib/2.15.1] [generic_x86, Android SDK built for x86, unknown, 23]
[ +368 ms] I/ExoPlayerImpl( 5641): Init 55a8915 [ExoPlayerLib/2.15.1] [generic_x86, Android SDK built for x86, unknown, 23]
[ +155 ms] W/VideoCapabilities( 5641): Unrecognized profile/level 0/0 for video/mpeg2
[   +2 ms] W/VideoCapabilities( 5641): Unrecognized profile/level 0/2 for video/mpeg2
[        ] W/VideoCapabilities( 5641): Unrecognized profile/level 0/3 for video/mpeg2
[  +37 ms] I/VideoCapabilities( 5641): Unsupported profile 4 for video/mp4v-es
[  +18 ms] I/OMXClient( 5641): Using client-side OMX mux.
[ +133 ms] E/OMXNodeInstance( 5641): setConfig(1:google.mp3.decoder, ConfigPriority(0x6f800002)) ERROR: Undefined(0x80001001)
[        ] I/ACodec  ( 5641): codec does not support config priority (err -2147483648)
[        ] E/OMXNodeInstance( 5641): setConfig(1:google.mp3.decoder, ConfigOperatingRate(0x6f800003)) ERROR: Undefined(0x80001001)
[        ] I/ACodec  ( 5641): codec does not support config operating rate (err -2147483648)
[+5288 ms] E/ExoPlayerImplInternal( 5641): Playback error
[        ] E/ExoPlayerImplInternal( 5641):   com.google.android.exoplayer2.ExoPlaybackException: Source error
[        ] E/ExoPlayerImplInternal( 5641):       at com.google.android.exoplayer2.ExoPlayerImplInternal.handleIoException(ExoPlayerImplInternal.java:624)
[        ] E/ExoPlayerImplInternal( 5641):       at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:594)
[        ] E/ExoPlayerImplInternal( 5641):       at android.os.Handler.dispatchMessage(Handler.java:98)
[        ] E/ExoPlayerImplInternal( 5641):       at android.os.Looper.loop(Looper.java:148)
[        ] E/ExoPlayerImplInternal( 5641):       at android.os.HandlerThread.run(HandlerThread.java:61)
[        ] E/ExoPlayerImplInternal( 5641):   Caused by: com.google.android.exoplayer2.ParserException: Loading finished before preparation is complete.
[        ] E/ExoPlayerImplInternal( 5641):       at com.google.android.exoplayer2.source.ProgressiveMediaPeriod.maybeThrowPrepareError(ProgressiveMediaPeriod.java:240)
[        ] E/ExoPlayerImplInternal( 5641):       at com.google.android.exoplayer2.source.MaskingMediaPeriod.maybeThrowPrepareError(MaskingMediaPeriod.java:154)
[        ] E/ExoPlayerImplInternal( 5641):       at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:995)
[        ] E/ExoPlayerImplInternal( 5641):       at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:482)
[        ] E/ExoPlayerImplInternal( 5641):       ... 3 more

Screen Shot 2021-12-30 at 13 41 06

Weav3r commented 1 year ago

@jhomlala This issue also occurs on android version 10.

Example to reproduce is the official cache example in this repository.

Steps to reproduce:

  1. Clone best player repository
  2. Update gradle (I updated to 7.5) and gradle_plugin (7.3.0). One can also clone this PR (not yet accepted use at your own risk) which updates the better_player (PR-1085)
  3. Must set videoFormat: BetterPlayerVideoFormat.hls
  4. Run example and play cache video example
  5. Navigate back
  6. Turn off internet
  7. Try to play video (Playback error "Source Error") occurs

Additional context

It is sometimes able to play the video when I navigate back while the video is still playing but only plays up to the buffered position.

On the contrary when an mp4 video is used it works without errors.

Steps to test mp4 video caching

  1. Remove videoFormat: BetterPlayerVideoFormat.hls if it is set.
  2. Change source url from Constants.phantomVideoUrl to Constants.verticalVideoUrl
  3. Run example and play cache video example
  4. Navigate back
  5. Turn off internet
  6. Playback video
  7. No error occurs

Flutter doctor

[✓] Flutter (Channel stable, 3.3.9, on Linux 6.1.1-arch1-1, locale en_GB.UTF-8)
    • Flutter version 3.3.9 on channel stable at /home/path/to/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision b8f7f1f986 (5 weeks ago), 2022-11-23 06:43:51 +0900
    • Engine revision 8f2221fbef
    • Dart version 2.18.5
    • DevTools version 2.15.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /home/path/to/android/sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /home/path/to/jre/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)

Better Player version

Version: ^0.0.83

Smartphone (please complete the following information):

Device: Huawei Y9 prime
OS: Android 10 (API 29)