3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Xamarin.Forms]VLCライブラリを使ってiOSでWebMを再生する方法

Posted at

やりたいこと

サーバ側でWebM形式で保存されている動画をダウンロードしてAndroidとiOSのアプリで再生したい。
Androidは標準のVideoViewでWebM形式の動画を再生することができるが、
iOSの動画プレーヤーはWebM形式には対応していないため、WebMを再生できるライブラリが必要...
再生中はシークバーと経過時間などを表示したい。

使用したライブラリ

多くのコーデックに対応しているVLCが提供しているライブラリLibVLCSharpを使えば、iOSでもWebMを再生できそう。
ただ、ライブラリを見てみるとVideoViewはあくまで動画再生部分のコントロールであって、シークバーなどは用意されていないため、自分で実装する必要がある。

使用するにあたって

  • LibVLCSharpはPCLには対応していないので.NETStandardにしなければならない。
  • Xamarin.Formsのバージョンを3.2.0以上にする。

実装方法(.NET Standardのライブラリ側)

  1. NuGetで「LibVLCSharp.Forms(0.5.0)」を追加。

  2. MainPage.xaml.cs(動画プレーヤーページ)のOnAppearingメソッドで初期化処理を記述。
    xaml側のソースは割愛します。詳しくは下記のGitHubを参照してください。

    MainPage.xaml.cs
    protected override void OnAppearing()
    {
        base.OnAppearing();
        
        // VLC Initialize
        Core.Initialize();
    
        var libVLC = new LibVLC();
        _media = new Media(libVLC, "http://www.quirksmode.org/html5/videos/big_buck_bunny.webm", FromType.FromLocation);
        
        VideoView.MediaPlayer = new MediaPlayer(libVLC) { Media = _media };
        VideoView.MediaPlayer.TimeChanged += OnMediaPlayerTimeChanged;
        VideoView.MediaPlayer.LengthChanged += OnMediaPlayerLengthChanged;
        VideoView.MediaPlayer.EndReached += OnMediaPlayerEndReached;
        PlaybackSlider.TouchUp += OnPlaybackSliderTouchUp;
        ...
    }
    
  3. 再生・一時停止ボタン押下処理

    MainPage.xaml.cs
    private void OnPlayImageButtonClicked(object sender, EventArgs e)
    {
        if (VideoView.MediaPlayer.State == VLCState.Playing)
        {
            // Pause
            VideoView.MediaPlayer.Pause();
            PlayImageButton.Source = _playImage;
        }
        else
        {
            if (VideoView.MediaPlayer.State == VLCState.Ended)
            {
                VideoView.MediaPlayer.Media = _media;
            }
    
            // Play
            VideoView.MediaPlayer.Play();
            PlayImageButton.Source = _pauseImage;
            Tool.IsVisible = true;
        }
    }
    
  4. LengthChangedイベントで動画の長さを保持

    MainPage.xaml.cs
    private void OnMediaPlayerLengthChanged(object sender, MediaPlayerLengthChangedEventArgs e)
    {
        _length = e.Length;
    }
    
  5. TimeChangedイベントで動画再生時の時間処理を記述

    MainPage.xaml.cs
    private void OnMediaPlayerTimeChanged(object sender, MediaPlayerTimeChangedEventArgs e)
    {
        var elapsedTimeSpan = TimeSpan.FromMilliseconds((double)e.Time);                // ElapsedTime
        var remainingTimeSpan = TimeSpan.FromMilliseconds((double)(_length - e.Time));  // RemainingTime
        var elapsedTotalSeconds = Math.Floor(elapsedTimeSpan.TotalSeconds);             // ElapsedTime(TotalSeconds)
    
        // Draw
        Device.BeginInvokeOnMainThread(() => {
            PlaybackSlider.Value = VideoView.MediaPlayer.Position;
        });
    
        if (Math.Abs(_elapsedTotalSeconds - elapsedTotalSeconds) < 1)
        {
            return;
        }
    
        // Backup TotalSeconds
        _elapsedTotalSeconds = elapsedTotalSeconds;
    
        // Draw(1Seconds)
        Device.BeginInvokeOnMainThread(() => {
            ElapsedTime.Text = string.Format("{0:D2}:{1:D02}", elapsedTimeSpan.Minutes, elapsedTimeSpan.Seconds);
            RemainingTime.Text = string.Format("{0:D2}:{1:D02}", remainingTimeSpan.Minutes, remainingTimeSpan.Seconds);
        });
    }
    
  6. EndReachedイベントで動画終了処理を記述

    MainPage.xaml.cs
    private void OnMediaPlayerEndReached(object sender, EventArgs e)
    {
        _elapsedTotalSeconds = 0;
    
        // Draw
        Device.BeginInvokeOnMainThread(() => {
            PlaybackSlider.Value = 0;
            PlayImageButton.Source = _playImage;
            Tool.IsVisible = false;
            ElapsedTime.Text = "00:00";
            RemainingTime.Text = "00:00";
        });
    }
    
  7. シークバーのタップイベントで動画のポジションを変更
    シークバーの詳しい実装については下記のGitHubを参照してください。

    MainPage.xaml.cs
    private void OnPlaybackSliderTouchUp(object sender, EventArgs e)
    {
        // Draw
        Device.BeginInvokeOnMainThread(() => {
            VideoView.MediaPlayer.Position = (float)sender;
        });
    }
    

実装方法(iOS側)

  1. NuGetで「VideoLAN.LibVLC.iOS(3.1.5-alpha)」を追加。
  2. シークバーのRendererを実装。(GitHubを参照)

実装方法(Android側)

  1. NuGetで「VideoLAN.LibVLC.Android(3.0.0)」を追加。
  2. シークバーのRendererを実装。(GitHubを参照)

注意点

Androidで動画ページから別ページに遷移したり、アプリをバックグラウンドに移行すると、
「[Adreno] DequeueBuffer: dequeueBuffer failed」のエラーが出続けてしまうので、
ページのOnDisappearingでVideoView.MediaPlayerを明示的にDisposeする必要がある。
App.xaml.csのOnSleepでもDisposeする。

実行

さすがVLCだけあって綺麗に動画が再生されました。

iOS

iOS

Android

Android

ソース

今後

動画の回転表示や、再生ボタンをオーバレイ化したい。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?