Xperia端末でVideoViewで動画再生時に緑色に点滅する現象を回避する

# はじめに

2017/12/11 ～ 12 にかけて調査した結果のログです。

拙作の[Twitterクライアント](https://play.google.com/store/apps/details?id=com.twitpane&hl=ja)のユーザーから「動画再生中にしばらくすると緑色に点滅する現象が発生するので何とかして欲しい」という報告がたびたび来ていました。

報告のあった端末をまとめると、いずれも Android 5.0～6.0 のXperia端末で、比較的長い動画の再生中に発生するという共通点がありました。

![2017-12-13_11h08_35.png](https://qiita-image-store.s3.amazonaws.com/0/39221/3e2ba811-aaec-83b3-a08d-4c7b77eebc26.png)

手元の SOL25 でも再現できたため、調査を開始。具体的には 30 秒ほどの動画を再生し、2ループ目で発生していました。

<!--
<blockquote class="twitter-video" data-lang="ja"><p lang="ja" dir="ltr">いくつかのXperia端末で動画再生中に緑色に点滅する現象を調査してるんだけど、なぜか AndroidStudio で Screen Record を開始するとすぐに解消する。それ相当のことをコードからやればいいんだろうけどどうすりゃいいんだ。 <a href="https://t.co/vJkA604gZ4">pic.twitter.com/vJkA604gZ4</a></p>&mdash; 竹内裕昭 (@takke) <a href="https://twitter.com/takke/status/940397271698489344?ref_src=twsrc%5Etfw">2017年12月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
-->


# アプリ側の調査

## VideoView 周辺のレイアウトを変えてみるなど

![2017-12-13_11h11_58.png](https://qiita-image-store.s3.amazonaws.com/0/39221/745b0d04-6008-1782-ba60-32cd66a15995.png)

VideoView は ConstraintLayout -> FrameLayout -> VideoView の中にあり、下にSeekBarや疑似ツールバーなど色々と配置されているのでこれらが原因で発生する可能性を疑い、RelativeLayout に変えてみたり、RelativeLayout -> VideoView だけのシンプルなレイアウトにしてみたりしたけど解決せず。

次にVideoViewを扱うコード側の問題を疑い、新規に VideoView だけ配置したActivity だけを持つアプリを作ってみたけどやはり現象は消えず。

## ループ処理周辺を疑う

2ループ目で発生するのでその周辺のコードを調べてみました。

```kotlin
        videoView.setOnCompletionListener {
            // ループ再生フラグの確認
            if (TPConfig.isMoviePlayerRepeating(applicationContext)) {

                // ループ再生
                videoView.seekTo(0)
                videoView.start()

                mPaused = false
            } else {
...
            }
        }
```

他にも SeekBar タップ時にもたまに発生するので、どうやら ```videoView.seekTo``` を使うと発生するっぽいことが見えてきました。

## WorkAround として

"VideoView flickering" "VideoView flash" などのキーワードで検索しまくった(数時間かけてわりとしらみつぶしに色んなコードを試した)のですが全く手がかりを得られず。

VideoView のソースを見ると ```SurfaceView``` + ```MediaPlayer``` なのでそれらと ```OpenGL``` 周辺の調査も必要かなぁと諦めかけ。

どこかの Stack Overflow で ```VideoView.resume()``` を ```re-buffering``` などと説明していたのを参考に、試しに ```seekTo(0)``` の前に ```resume()``` を呼んでみると本現象はひとまず発生しなくなった。とはいえ ```resume()``` すると少し再生が止まるので綺麗なループ再生が出来なくなり、全端末で採用するのはキツイ WorkAround でした。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">VideoView(=MediaPlayer).seekTo() の前に resume() で内部バッファとか色々クリアしてやると一応現象的には収まるんだけど、長い動画の再生中に突然発生する場合もあるんでそのパターンはまだ解決策が分からない。</p>&mdash; 竹内裕昭 (@takke) <a href="https://twitter.com/takke/status/940398243195654145?ref_src=twsrc%5Etfw">2017年12月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



# 現象の特定と設定値の条件


## Screen Record すると改善される？

Android Studio の logcat タブの Screen Record 機能を使って本現象を録画してみようとしたところ、録画を開始してすぐに点滅現象が収まることが分かりました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">いくつかのXperia端末で動画再生中に緑色に点滅する現象を調査してるんだけど、なぜか AndroidStudio で Screen Record を開始するとすぐに解消する。それ相当のことをコードからやればいいんだろうけどどうすりゃいいんだ。 <a href="https://t.co/vJkA604gZ4">pic.twitter.com/vJkA604gZ4</a></p>&mdash; 竹内裕昭 (@takke) <a href="https://twitter.com/takke/status/940397271698489344?ref_src=twsrc%5Etfw">2017年12月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

すると某先輩から有力な手がかりが。

<blockquote class="twitter-tweet" data-conversation="none" data-lang="en"><p lang="ja" dir="ltr">この緑になるやつXperiaで昔から起こる現象っぽいよね。<br>開発者オプションか画面設定の「動画再生時の高画質処理」が悪さしてるような気はするけど。</p>&mdash; gunyuu3 (@gunyuu3) <a href="https://twitter.com/gunyuu3/status/940401111671775234?ref_src=twsrc%5Etfw">December 12, 2017</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

試してみると確かに Xperia 端末の設定画面にある「画面設定」⇒「高画質モード」を「X-Reality for mobile」から「オフ」にすると本現象は全く発生しなくなることが分かりました。Xperiaめ！

噂では YouTube アプリでも同様の現象が起きるようなのでまた少し諦めかけ。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">試したところ、確かに「動画設定」⇒「高画質モード」を「X-Reality for mobile」(既定値)から「OFF」にすると緑色の点滅現象は起きなくなった。これをコードから呼び出せれば(高画質モードを一時的にオフにできれば)いいのか。詳しい人教えてください。。</p>&mdash; 竹内裕昭 (@takke) <a href="https://twitter.com/takke/status/940402450137210881?ref_src=twsrc%5Etfw">2017年12月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">xperia の高画質モード使ってないので気付かなかったが、高画質モード入れると、youtube とかも緑画面になることがあるのか</p>&mdash; 生きた人工無能（生体版 ELIZA） (@feelwavy) <a href="https://twitter.com/feelwavy/status/940404431366918144?ref_src=twsrc%5Etfw">2017年12月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>




## Xperia端末の高画質モードの設定値を探す

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Xperia端末の高画質モード設定をアプリから取得するのってどうすればいいんだろう。/proc/とかに設定値置いてあったりしないよな。</p>&mdash; 竹内裕昭 (@takke) <a href="https://twitter.com/takke/status/940432499422855169?ref_src=twsrc%5Etfw">2017年12月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

"how to get x-reality mode" のようなキーワードで探しまくるも端末の設定から変更するものばかり。

X-Reality モードはソニー自慢の BRAVIA エンジン(かな？)を Xperia 端末に導入したもので、動画再生中に適用されるものらしい。最新のXperia端末には最新の X-Reality が入っていて、それを少し古い端末でも使えるようにする APK が非公式に配布されていたりしていました。

"xperia x-reality mode java" で検索してたどり着いた [\[Tut\]\[MoD\]\[Xperia devices\] Bravia/Supervivid/x\-reality](https://forum.xda-developers.com/crossdevice-dev/sony/tut-bravia-supervivid-x-reality-t2974239) もその解説記事でしたが、その一部に設定画面を変更する部分がありました。

![2017-12-13_11h42_42.png](https://qiita-image-store.s3.amazonaws.com/0/39221/e75b60e4-a4be-a83a-61e1-15aea8f2d3dc.png)

というわけで、「高画質モード」の設定画面が "com.sonymobile.imageenhancer" で提供されていることが分かりました。


<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Xperia端末の画面設定にある高画質モードは com.sonymobile.imageenhancer を呼び出していることが分かったのでごにょごにょして調べてるところ。</p>&mdash; 竹内裕昭 (@takke) <a href="https://twitter.com/takke/status/940440401927794688?ref_src=twsrc%5Etfw">2017年12月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## APK を持ってくる

手元の SOL25 の実機から "com.sonymobile.imageenhancer" を持ってきます。

[Android 実機から apk を探して取得 \- clock\-up\-blog](http://blog.clock-up.jp/entry/2015/02/28/android-pull-apk) を参考に、

```bash
$ adb shell pm list packages -f
...
package:/system/app/ImageEnhancer/ImageEnhancer.apk=com.sonymobile.imageenhancer
...
```

で該当パッケージのAPKフルパスを取得できるので、

```bash
$ adb pull /system/app/ImageEnhancer/ImageEnhancer.apk
```

でAPKを取得。

## ごにょごにょする

あとは APK をごにょごにょして調べます。


<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Xperia端末の高画質モードは SystemProperties.getInt(&quot;persist.service.xrfm.mode&quot;, 0) といったコードで取得できた。</p>&mdash; 竹内裕昭 (@takke) <a href="https://twitter.com/takke/status/940475176323399680?ref_src=twsrc%5Etfw">2017年12月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


## SystemProperties から取得する

直接は呼び出せないのでリフレクションなどで該当する値を取得したところ、確かに高画質モードの設定画面で変更した値を取得できました。

## というわけで、

先ほどの ```VideoView.resume()``` を ```VideoView.seekTo()``` の前に実行するという WorkAround を「Android 6.0以下 で ```persist.service.xrfm.mode``` がOn(0以外)の場合にのみ実行する」ことで最小限の端末で WorkAround を実行できるようになりました。



# おしまい

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">昨日からずっと動画再生中の緑点滅問題を追いかけていて、調査用に1activity、VideoViewだけのアプリ作ってみたり、VideoViewのいろんなメソッド呼んで改善しないか試したり、Xperiaの設定画面のAPKをごにょごにょしてプロパティ特定したり、さすがに疲れた。原因は分かったからひとまず本件はおしまい <a href="https://t.co/5PsC5dGtDS">pic.twitter.com/5PsC5dGtDS</a></p>&mdash; 竹内裕昭 (@takke) <a href="https://twitter.com/takke/status/940492794484858880?ref_src=twsrc%5Etfw">2017年12月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>