jakky1 / video_player_win

Flutter video player for Windows, lightweight, using Windows built-in Media Foundation API. Windows implementation of the video_player plugin.
BSD 3-Clause "New" or "Revised" License
35 stars 11 forks source link

[BUG] Load video file if flac audio in mp4 #10

Open narumi147 opened 1 year ago

narumi147 commented 1 year ago

After update to flutter 3.10 No related to flutter 3.10 video player always failed to load video file. VideoPlayerController.initialize didn't throw the error, the win plugin only printed

[video_player_win] load fail, reload now
[log] [video_player_win] playback event: error

Since the error is not thrown, the app will treat it as initiated and playing(though it is errored). when calling pause. it will throw

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument(s): video file not opened yet
#0      WinVideoPlayerController.pause         video_player_win.dart:200
#1      WindowsVideoPlayer.pause               video_player_win_plugin.dart:77
#2      VideoPlayerController._applyPlayPause  video_player.dart:555
#3      VideoPlayerController.pause            video_player.dart:516

Maybe errored before 3.10

jakky1 commented 1 year ago

I test on 3.10 now, and it works well for me.

Could you tell me which video file / url you are playing?

narumi147 commented 1 year ago

https://static.atlasacademy.io/JP/Movie/talk_mov169.mp4

app downloaded it first, then create controller via Controller.file(). The default win10 player can play the file normally.

Tried on 2 windows devices, the same error.

jakky1 commented 1 year ago

To clarify, some (and I think almost) video files are playable with this package. Only some video files play failed.

Unfortunately, the video file you provided play failed with this package, although I know Window Media Player can play it.

I also tried the Microsoft official sample code topoedit & protectedplayback, which are use Microsoft Media Foundation topology API too, they also cannot play the video file you provided, but can play my other video files well.

Since the above 2 official Microsoft samples play failed too, so I have no idea how to solve this issue... orz Maybe you should try other packages if it's really a problem for you :(

narumi147 commented 1 year ago

turned out it was because of audio format. This mp4 is h264 video + flac audio, and Media Foundation doesn't support flac format. Now the audio format has changed to aac, and it works fine.

But in v1 plugin, I remember it can play the file, when I first introduce this plugin to app. Not sure what's the difference between v1 and v2, even if they both use Media Foundation API.

So I guess here are something we can improve:

  1. point to the above format support page of Media Foundation in README, if that link is the api what you use.
  2. throw error in Controller initiate, so I can handle the error such as alert user or redownload new file. (Is load fail, reload now printed during controller init?)
  3. In README, add dart identifier in code block to give it syntax hightlight
narumi147 commented 1 year ago

I saw you set value = value.copyWith(isInitialized: false, hasError: true, isPlaying: false) after error. But that's WinVideoPlayerValue which I cannot get from VideoPlayerController.value/VideoPlayerValue. And after error, the VideoPlayerValue is kept InInitiated true, didn't update to false.

jakky1 commented 1 year ago

About FLAC format, I tried these flac file, and this package can play them.

So I think the FLAC format is supported if K-lite codec installed.

I also tried to ignore any audio tracks, and this package can play the file you provided. (of course only video, no audio)

Your video file maybe has some unusual data, and the codec just cannot handle it. But this cannot explain why Windows Media Player can play it... (but official Microsoft sample code cannot play it, mentioned before)

About the error handling improvement you asked, because the codec doesn't report error in normal way, so I cannot do as your wish.

Why I print load fail, reload now, because when playing a video successfully, there are many state-change occurs in MyPlayer::Invoke method, but when playing your video file, or when playing network url failed if socket timeout, the state-change acts in a different way, so I will reload it. But I cannot distinguish them, so I cannot just report error to user. And if codec cannot parse file successfully, it should return false in BeginCreateObjectFromURL and in its callback, but it didn't in your video file. So currently I won't change the code.

narumi147 commented 1 year ago

Thanks for the detailed research!

First sorry i didn't tell that I don't install extra decoder like K-Lite, just want to suggest pointing out what formats are supported by default only with this plugin. And I saw your commit, that's what I want.

Then as for the main appeal, if it's not possible to report error to user at present. Is it possible to update VideoPlayerValue.IsInitialized from WinVideoPlayerControllerValue if error happened and the video is actually not playing? So I can check IsInitialized to decide to redownload file or not.

annd22 commented 4 months ago

is there any update on this?

jakky1 commented 4 months ago

@annd22, narumi147 has pointed out the following 2 questions:

** flac audio not support K-lite codec pack support it, and he has clarified that he not installed K-lite codec pack so load failed (May 14, 2023 post)

** WinVideoPlayerValue.IsInitialized is not passed to VideoPlayerValue.IsInitialized I just test it 1 minute ago and it works fine.

annd22 commented 4 months ago

** WinVideoPlayerValue.IsInitialized is not passed to VideoPlayerValue.IsInitialized I think this is not correct.

At the file video_player_win.dart, case 7, I have to fork the project and modify:

case 7: // MEError
        log("[video_player_win] playback event: error");
        value = value.copyWith(
            isInitialized: false, hasError: true, isPlaying: false);
       // <-- add event to update isInitialized to false
        _eventStreamController.add(VideoEvent(
          eventType: VideoEventType.initialized, duration: null, size: null));
        _cancelTrackingPosition();
        break;

Without the modified code, the value of isInitialized don't updated.

jakky1 commented 4 months ago

@annd22, Thanks for the code patch.

I try to fix it and upload to github. Please try it and let me know if it works in your case.

dependencies:
  video_player_win:
    git:
      url: https://github.com/jakky1/video_player_win.git
      ref: master