Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS 16][video_player] Some videos play only audio with no video #111457

Closed
collinNewCode opened this issue Sep 13, 2022 · 34 comments · Fixed by flutter/plugins#6442
Closed

[iOS 16][video_player] Some videos play only audio with no video #111457

collinNewCode opened this issue Sep 13, 2022 · 34 comments · Fixed by flutter/plugins#6442
Assignees
Labels
e: OS-version specific Affects only some versions of the relevant operating system found in release: 3.3 Found to occur in 3.3 found in release: 3.4 Found to occur in 3.4 has reproducible steps The issue has been confirmed reproducible and is ready to work on p: video_player The Video Player plugin P1 High-priority issues at the top of the work list package flutter/packages repository. See also p: labels. platform-ios iOS applications specifically r: fixed Issue is closed as already fixed in a newer version

Comments

@collinNewCode
Copy link

the video_player plugin to play AES-128 encrypted m3u8, the audio is working,but the video is black screen.
It was normal before iOS16.

Unencrypted m3u8 seems to be normal.
Can anyone give me some guidance?

@danagbemava-nc danagbemava-nc added the in triage Presently being triaged by the triage team label Sep 13, 2022
@danagbemava-nc
Copy link
Member

Hi @collinNewCode,

Please provide your flutter doctor -v and a minimal complete reproducible code sample.

Also, what version of video_player are you using?

Thank you

@danagbemava-nc danagbemava-nc added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Sep 13, 2022
@hucool
Copy link

hucool commented Sep 13, 2022

I have the same problem

func copyPixelBuffer always returns null

video_player version: 2.4.7

test video url: https://service.beta.sanjieke.cn/video/media/11244355/608p.m3u8?user_id=18942194&class_id=33254014&time=1663055202&nonce=868849&token=73daa6bce6e2643a3a9d2f28f3385ce86fa5ec82

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Sep 13, 2022
@collinNewCode
Copy link
Author

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

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

class MyVideo extends StatefulWidget {
  const MyVideo({Key? key}) : super(key: key);

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

class _MyVideoState extends State<MyVideo> {
  VideoPlayerController? _controller;

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("My Video"),
      ),
      body: Center(
        child: _controller!.value.isInitialized
            ? AspectRatio(
                aspectRatio: _controller!.value.aspectRatio,
                child: VideoPlayer(_controller!),
              )
            : Container(
                child: const Text('loading...'),
              ),
      ),
    );
  }

  Future<void> init() async {
    _controller = VideoPlayerController.network(
      'https://service.beta.sanjieke.cn/video/media/11244355/608p.m3u8?user_id=18942194&class_id=33254014&time=1663055202&nonce=868849&token=73daa6bce6e2643a3a9d2f28f3385ce86fa5ec82',
    );

    _controller?.addListener(() {
      setState(() {});
    });

    await _controller?.initialize();

    _controller?.play();
  }
}
[✓] Flutter (Channel stable, 3.0.5, on macOS 13.0 22A5342f darwin-x64, locale zh-Hans-CN)
    • Flutter version 3.0.5 at /Users/admin/Documents/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision f1875d570e (9 周前), 2022-07-13 11:24:16 -0700
    • Engine revision e85ea0e79c
    • Dart version 2.17.6
    • DevTools version 2.12.2

[✗] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from: https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK components.
      (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
      If the Android SDK has been installed to a custom location, please use
      `flutter config --android-sdk` to update to that location.


[!] Xcode - develop for iOS and macOS (Xcode 14.0)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    ! CocoaPods 1.10.1 out of date (1.11.0 is recommended).
        CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin usage on the Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To upgrade see https://guides.cocoapods.org/using/getting-started.html#installation for instructions.

[✗] Chrome - develop for the web (Cannot find Chrome executable at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[!] Android Studio (not installed)
    • Android Studio not found; download from https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).

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

[✓] Connected device (2 available)
    • iPhone (mobile) • d2ceb261b299406c50174a51869db35845cf8659 • ios        • iOS 16.0 20A362
    • macOS (desktop) • macos                                    • darwin-x64 • macOS 13.0 22A5342f darwin-x64

[✓] HTTP Host Availability
    • All required HTTP hosts are available

video_player version: 2.4.7

@danagbemava-nc

@danagbemava-nc danagbemava-nc changed the title [iOS 16]video_player is black [iOS 16][video_player] Some videos play only audio with no video Sep 13, 2022
@danagbemava-nc
Copy link
Member

danagbemava-nc commented Sep 13, 2022

I can reproduce the issue with the code sample provided above.
I tested a swiftUI app and everything worked as expected.

Edit: I only tested on iOS 16 since I do not have an iOS 15 device at the moment

videos
flutter swiftUI
Simulator.Screen.Recording.-.iPhone.14.Pro.-.2022-09-13.at.13.24.53.mp4
Simulator.Screen.Recording.-.iPhone.14.Pro.-.2022-09-13.at.13.32.58.mp4
swiftUI sample
import AVKit
import SwiftUI

struct ContentView: View {
        
    let videoURL = "https://service.beta.sanjieke.cn/video/media/11244355/608p.m3u8?user_id=18942194&class_id=33254014&time=1663055202&nonce=868849&token=73daa6bce6e2643a3a9d2f28f3385ce86fa5ec82"
    @State var showingErrorAlert = false
    @State var errorMessage = ""
    @State var alertTitle = ""
    @State var player : AVPlayer = AVPlayer()
    
    var body: some View {
        VideoPlayer(
            player: player
        ).frame(height: 400)
        .onAppear(perform: playVideo)
        .alert(alertTitle, isPresented: $showingErrorAlert) {
            Button("OK") {}
        } message: {
          Text(errorMessage)
        }
    }
    
    func playVideo() -> Void {
        guard let url = URL(string: videoURL) else {
            alertTitle = "Error"
            errorMessage = "Unable to play video"
            showingErrorAlert = true
            return
        }
        
        player = AVPlayer(url: url)
        
        player.play()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
flutter sample
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

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

class MyVideo extends StatefulWidget {
  const MyVideo({Key? key}) : super(key: key);

  @override
  State<MyVideo> createState() => _MyVideoState();
}

class _MyVideoState extends State<MyVideo> {
  VideoPlayerController? _controller;

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("My Video"),
      ),
      body: Center(
        child: _controller!.value.isInitialized
            ? AspectRatio(
                aspectRatio: _controller!.value.aspectRatio,
                child: VideoPlayer(_controller!),
              )
            : Container(
                child: const Text('loading...'),
              ),
      ),
    );
  }

  Future<void> init() async {
    _controller = VideoPlayerController.network(
      'https://service.beta.sanjieke.cn/video/media/11244355/608p.m3u8?user_id=18942194&class_id=33254014&time=1663055202&nonce=868849&token=73daa6bce6e2643a3a9d2f28f3385ce86fa5ec82',
    );

    _controller?.addListener(() {
      setState(() {});
    });

    await _controller?.initialize();

    _controller?.play();
  }
}
flutter doctor -v
[✓] Flutter (Channel stable, 3.3.1, on macOS 12.5 21G72 darwin-arm, locale en-GB)
    • Flutter version 3.3.1 on channel stable at /Users/nexus/dev/sdks/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 4f9d92fbbd (7 days ago), 2022-09-06 17:54:53 -0700
    • Engine revision 3efdf03e73
    • Dart version 2.18.0
    • DevTools version 2.15.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /Users/nexus/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/212.5712.43.2112.8815526/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.0)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14A309
    • CocoaPods version 1.11.3

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

[✓] Android Studio (version 2021.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] Android Studio (version 2021.2)
    • Android Studio at /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/212.5712.43.2112.8815526/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

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

[✓] Connected device (3 available)
    • iPhone 14 Pro (mobile) • 4302007A-B132-4B89-887A-C5993FCA3284 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-16-0 (simulator)
    • macOS (desktop)        • macos                                • darwin-arm64   • macOS 12.5 21G72 darwin-arm
    • Chrome (web)           • chrome                               • web-javascript • Google Chrome 105.0.5195.102

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!
[✓] Flutter (Channel master, 3.4.0-19.0.pre.220, on macOS 12.5 21G72 darwin-arm64, locale en-GB)
    • Flutter version 3.4.0-19.0.pre.220 on channel master at /Users/nexus/dev/sdks/flutters
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 64b008ab87 (9 hours ago), 2022-09-13 00:33:38 -0400
    • Engine revision 66823c7518
    • Dart version 2.19.0 (build 2.19.0-191.0.dev)
    • DevTools version 2.17.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /Users/nexus/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/212.5712.43.2112.8815526/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.0)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14A309
    • CocoaPods version 1.11.3

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

[✓] Android Studio (version 2021.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] Android Studio (version 2021.2)
    • Android Studio at /Users/nexus/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/212.5712.43.2112.8815526/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

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

[✓] Connected device (3 available)
    • iPhone 14 Pro (mobile) • 4302007A-B132-4B89-887A-C5993FCA3284 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-16-0 (simulator)
    • macOS (desktop)        • macos                                • darwin-arm64   • macOS 12.5 21G72 darwin-arm64
    • Chrome (web)           • chrome                               • web-javascript • Google Chrome 105.0.5195.102

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

@danagbemava-nc danagbemava-nc added platform-ios iOS applications specifically plugin p: video_player The Video Player plugin has reproducible steps The issue has been confirmed reproducible and is ready to work on found in release: 3.3 Found to occur in 3.3 found in release: 3.4 Found to occur in 3.4 e: OS-version specific Affects only some versions of the relevant operating system labels Sep 13, 2022
@collinNewCode
Copy link
Author

我可以使用上面提供的代码示例重现该问题。 我测试了一个 swiftUI 应用程序,一切都按预期工作。

编辑:我只在 iOS 16 上进行了测试,因为我目前没有 iOS 15 设备

视频
swiftUI 示例
颤振样本
颤振医生-v

@danagbemava-nc
Currently this issue only exists in iOS 16.
bro, is there a temporary solution now

@danagbemava-nc
Copy link
Member

bro, is there a temporary solution now

Not that I'm aware of at the moment. Someone from the plugins team will take a look at this soon

@hellohuanlin
Copy link
Contributor

I was able to reproduce. The [_videoOutput hasNewPixelBufferForItemTime:] always return false in iOS 16.

@collinNewCode
Copy link
Author

I was able to reproduce. The [_videoOutput hasNewPixelBufferForItemTime:] always return false in iOS 16.

yes,do u have a solution now?

@hellohuanlin
Copy link
Contributor

hellohuanlin commented Sep 14, 2022

@collinNewCode not yet, but i found this similar problem. It was 5 years ago, but could be same problem, just with different format

@darshankawar darshankawar removed the in triage Presently being triaged by the triage team label Sep 14, 2022
@oopuuu

This comment was marked as duplicate.

@JiangJuHong

This comment was marked as duplicate.

@wawo458

This comment was marked as duplicate.

@Adherentman

This comment was marked as off-topic.

@wawo458

This comment was marked as off-topic.

@collinNewCode

This comment was marked as off-topic.

@hellohuanlin hellohuanlin self-assigned this Sep 15, 2022
@hellohuanlin
Copy link
Contributor

I'm still looking into this. If you find anything that might be helpful, feel free to share as well.

@wawo458

This comment was marked as off-topic.

@Jai05-techie

This comment was marked as off-topic.

@jmagman
Copy link
Member

jmagman commented Sep 15, 2022

This is actively being worked on. Please avoid commenting “me too”, “+1”, or similar on issues. Instead, please add a thumbs-up reaction to the issue to avoid adding noise. If you’d like to receive updates, click the subscribe button in the right-hand column.

@stuartmorgan stuartmorgan added the P1 High-priority issues at the top of the work list label Sep 15, 2022
@hellohuanlin
Copy link
Contributor

Update: found some leads. Putting up a PR soon.

@hellohuanlin
Copy link
Contributor

hellohuanlin commented Sep 16, 2022

Update: It worked!

I am adding some unit tests and will put up a PR soon. But in case you are curious (it's a pretty tricky one), here's some info:

Research

There aren't too much info online. It seems to be by design that only Apple's AVPlayerLayer can access those encrypted video stream on iOS 16.

For example, this unresolved issue (5 years ago, but could be the same issue under different format):

the only way to display your protected video content is by using an AVPlayerLayer

Another hint is that iOS 16 introduced a new API AVPlayerLayer::copyDisplayedPixelBuffer with a note:

It also returns nil when displaying protected content

Reverse Engineering

I almost concluded that there's no way to solve it. But i was wondering "how did Apple solve it in AVPlayerLayer"? It must have accessed some private APIs. Something like this:

    if player.videoStream.someMetaData.isProtected {
      player.videoStream._unlockProtectedContent() // a hypothetical private API
    }

If I were to design AVFoundation, I would probably make it a layered structure, so that the "unlocked" pixel buffers can be piped downstream. This mean that "unlocking" probably happens towards the upstream, hence all outputs (including ours!) can be granted the access. Something like this:

graph TD;
  A[upstream input]-->B[...];
  B-->C[_unlock, hypothetical private API used by AVPlayerLayer];
  C-->D[...];
  D-->E[...]
  E-->F[output 1];
  E-->G[output 2];
  E-->H[output used by AVPlayerLayer];
  E-->I[output used by us];
Loading

To verify this hypothesis, I created a dummy AVPlayerLayer (without adding it to screen), hoping that the hypothetical unlocking happens in the constructor. The result is that only first video frame is displayed, and all other frames are still not accessible.

This tells 3 things:

  1. The above layered structure is likely what Apple is doing
  2. The hypothetical unlocking did happen in the constructor, but only for the first frame.
  3. The "unlocking" process is likely for each specific frame, and not the whole stream

Now based on all the above info, this is what I guess Apple's implementation of AVPlayerLayer is:

class AVPlayerLayer { 
  // `init` only unlocks the first frame 
  init(player: AVPlayer) {
    player.videoStream.firstFrame()._unlockFrame() // hypothetical private API
  }

  // each subsequent frame is unlocked separately
  func renderNextFrame() { 
    player.videoStream.frameAtCurrentTime()._unlockFrame() // hypothetical private API

    // now these pixel buffers become accessible
    let pixelBuffer = ... 
    paintOnCanvas(pixelBuffer)
  }
}

So in conclusion, all we need to do is to have an invisible AVPlayerLayer to concurrently play the video, which should invoke this hypothetical renderNextFrame() function, and eventually unlock every single frame for us.

And it worked :)

ios 16 video

Future

It is pretty obvious that Apple's intention is to only allow AVPlayerLayer to access those pixel buffers from iOS 16 onwards.

To follow this spirit, in the future we should probably rely on platform views with AVPlayerLayer attached. This would be a huge change from the current implementation though.

@jmagman
Copy link
Member

jmagman commented Sep 16, 2022

all we need to do is to have an invisible AVPlayerLayer to concurrently play the video

Are there memory or performance implications of doing this?

@hellohuanlin
Copy link
Contributor

Are there memory or performance implications of doing this?

@jmagman my guess is very minimal because it's not rendered on screen. But let me try and compare.

@hellohuanlin
Copy link
Contributor

I loop the video for around 20 minutes, and confirmed minimal performance impact:

Memory without the workaround:

wihtout workaround memory

Memory with the workaround:

memory with workaround

CPU without the workaround:

without workaround cpu

CPU with the workaround:

with workaround cpu

@Adherentman
Copy link

Approximately when the new version will be released?

@hellohuanlin
Copy link
Contributor

@Adherentman it should already be released when the PR is landed. Can you update and see if the issue is fixed?

@Adherentman
Copy link

Adherentman commented Sep 26, 2022

@Adherentman it should already be released when the PR is landed. Can you update and see if the issue is fixed?

@hellohuanlin

What do I need to do to test?

In pub.dev I checked video_player plugin version 2.4.7.

The version of video_player_avfoundation in the video_player plugin of the main branch in the github repository is 2.2.17

@hellohuanlin
Copy link
Contributor

@Adherentman Hmmm, I saw that video_player_avfoundation in pub.dev is still 2.3.5 (link). For some reason my update (2.3.6) is not published immediately. I thought the package is always auto released? Maybe the release process is broken? Let me take a look.

@jmagman
Copy link
Member

jmagman commented Sep 26, 2022

2.3.6 is now available. It was delayed due to https://github.com/flutter/plugins/actions/runs/3109769619 which failed on ios-platform_tests CHANNEL:master PACKAGE_SHARDING:--shardIndex 3 --shardCount 4: completed (failure), so the flaky integration test that you already turned off.

@hellohuanlin
Copy link
Contributor

@jmagman Gotcha. The website still shows 2.3.5 though: https://pub.dev/packages/video_player_avfoundation/versions

@hellohuanlin
Copy link
Contributor

hellohuanlin commented Sep 27, 2022

FYI there are some issue releasing it. It's being discussed in the discord channel. The sheriff will release it tomorrow.

@stuartmorgan
Copy link
Contributor

video_player_avfoundation 2.3.6 is published now; flutter pub upgrade will get the new version.

@Adherentman
Copy link

It's work. Thanks!

@github-actions
Copy link

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.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 12, 2022
@flutter-triage-bot flutter-triage-bot bot added the package flutter/packages repository. See also p: labels. label Jul 5, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
e: OS-version specific Affects only some versions of the relevant operating system found in release: 3.3 Found to occur in 3.3 found in release: 3.4 Found to occur in 3.4 has reproducible steps The issue has been confirmed reproducible and is ready to work on p: video_player The Video Player plugin P1 High-priority issues at the top of the work list package flutter/packages repository. See also p: labels. platform-ios iOS applications specifically r: fixed Issue is closed as already fixed in a newer version
Projects
None yet
Development

Successfully merging a pull request may close this issue.