開発者の視点:解析と HTML5 動画

開発者の視点:解析と HTML5 動画

「問題というのは全てが難しい」と言うのが口癖の私の同僚がいます。これにはちょっと言いたいことがあるのですが、ウェブ上の動画再生という点で言えば、まさに的を射ています。ある動画で人気のある場面をトラッキングする苦労を考えてみてください。どの視聴者がどの部分をどのくらいの時間見たのかを追跡する。ただウェブで少し調べたら、プレイバック中に可能な色々な種類のHTML標準イベントや情報が見つかります。これらを見ると、よくある難解なようで「簡単な問題」だと思うかもしれません。が、騙されてはいけません! あなたが標準準拠のデスクトップ ブラウザだけを気にしていれば良いラッキーな人でないのなら、この先に進みましょう。覚悟してくださいね。

Brightcove Video Cloud は、何百もの異なるデバイス・OS・ブラウザで閲覧された動画プレイバックをトラッキングするリアルタイムの解析機能を備えています。Video Cloud が収集する有益なデータの 1 つが動画エンゲージメントです。基本的にプレイバックの視聴数を 1 秒ごとにカウントし、視聴者がコンテンツのどの部分に一番興味を持ったのかを手軽に調べることができます。このシンプルさから、プログラミングも簡単かと思うかもしれませんが、実はそうではありません。モバイル デバイスの限定された帯域幅・バッテリー・処理能力、動画プレイバックと視聴者のアテンション スパンの非同期性、再生時のエラーやコンフリクトなど、対処すべき領域は多岐にわたります。

動画解析レポート作成の最初のステップは、通常のプレイバックでの視聴時間が何秒かを把握することです。これには、プレイバック中の「エンゲージメント」イベントを、1 秒ごとにバックエンドの解析システムに記録していくのがベストかもしれません。おそらく極めて有効な方法だと思います。ただ、この方法を取ることに躊躇する人がいたとしても、それはごもっともなことです。HTTP リクエストを毎秒送り続けることで、携帯電話のバッテリーと帯域幅がいたずらに消費されてしまいますから。でも実は、もっとスマートなやり方があります。エンゲージメント イベントをまとめて、より適切な頻度でレポーティングするのです。このようにほんの少し最適化することで、シンプルながら効果的なレポーティングが可能になります。プレイバック中に視聴者がポーズ(pause:一時停止)やシーク(seek:頭出し)を一度もしなかった場合には、これで完了です! ただ、残念ながらポーズやシークがあった場合は、ちょっとややこしくなります。

2 つのうちポーズのほうがずっとシンプルなので、まずはこちらから取りかかりましょう。視聴時間をまとめてレポーティングしているため、現時点ではブラウザ内の情報とバックエンドの情報は同期していません。例えば動画を 9 秒見た後にポーズを押して、そのまま戻ってこなかったとしたら、視聴時間の大部分については何も分からないままです。これはかなり良く起こる事態ですので、プレイバック中にポーズが発生するたびに現在トラッキングしているエンゲージメントをフラッシュして、大量のデータロスが発生しないようにしています。この手法ではトラッキング用にユーザの帯域幅をより多く使用しますが、大量の不正データを削除することで対応しています。一方、シークの場合は、より微妙なソリューションが求められます。

HTML5 では seeking と seeked のイベントを定義していますが、目的にマッチした現在のプレイバック ポジションの算出法との整合性は低いのが現状です。理想は、シークを開始したタイミングをキャプチャすることです。そうすれば、その時点までトラッキングしていたすべてのエンゲージメントをレポーティングし、シークが完了した時点でまた新たなデータの収集を開始できます。しかしながら、シークをスタートさせる API では現在の時間を直接上書きする必要があるため、シーク中に実時間を計測する良い方法がありません。ただこれは、最後の timeupdate イベント時の currentTime の値を記録することで解決できます。一点、シークが連続してなされた場合やシーク中に timeupdate がなされた場合は、古い値を再利用できないことに注意しなければなりません(これは単に記録上の問題だと思われます)。このように今や、極めて有効な動画エンゲージメントのレポーティング ツールが揃いました。あと残っているのは、Android を最新版にアップグレードしていないユーザが現在でも使用している Android 2.x 搭載デバイスへの対応だけです。

旧型デバイスの多くはイベントのシークに全く対応していません。そこでハイブリッド型のソリューションを試してみることにしました。大半のケースではシーク イベントにもとづく戦略を採用し、イベントをあてにできないプラットフォームではフォールバックの手法に頼りました。フォールバック方式は脆弱性が高いかもしれないと懸念していましたが、1 つではなく 2 つのコードパスをキープしているかのような感じです。この場合、イベントなしにシークをきちんと探知できるのか、という質問が当然出てくると思います。ただ少し考えると、2 つの timeupdate の間にある currentTime のギャップがシークであることがお分かりになると思います。この直感を形にするのは少々骨が折れます。

理論上、 currentTime をプレイバック中にサンプリングしている 1 つの関数として考えることができます。プレイバック中のすべてのポイントの値にアクセスできるとしたら、グラフの通り、シークは 2 本の線が途切れている箇所になります。

実際は、約 45 度の角度で左下から右上へと伸びる点線となります(点線の間隔は不均一)。グラフに表すとこのようになります。

こちらは格段にトリッキーです。すべての点をつなぐ線を引くとすると、シークの時間は角度が一番大きい(より垂直に近い)線になります。学生時代に勉強した微積分の記憶を思い起こすと、シークは関数の導関数が 1 よりはるかに大きい期間であるともいえます。導関数の数式に当てはめるのはとても有効です。というのも、すでに十分に検証された手法が数多く存在するからです。ただ、Google で "html5 detect video seeks" と検索するのは面白みに欠けます。

このアプローチが複雑ではないとは言えません。グラフ上の点線は通常、等間隔で並ばないでしょう。また、ブラウザがコンテンツを「リアルタイム」で途切れることなくプレイバックできると仮定して問題ないかという点も考慮しなければなりません。様々なプラットフォームで実施した測定結果を総合すると、少なくともプレイバックの開始時点では、動画のタイムラインは実際の時間よりもかなりゆっくり進んでいる可能性があります。最後に、記録された時間の信頼性についても疑問が残ります。多くのプラットフォームでは、実際にプレイバックされるのは専用ハードウェア上であり、その場合スピードと測定時の正確性がトレードオフになることがあります。同様のトレードオフやキャッシングは電気回路と視聴者のブラウザの間で、どの階層においても起こり得ます。これらの要素はどれも測定時のノイズとなり、理想の currentTime 関数において不連続点が誤って発生する原因となる可能性があるわけです。

これらの複雑な要因をすべて考慮すると、経時的にはこの導関数をどのように見積ることができるでしょう?ポーリング間隔が一定だとしたら、測定値の絶対差に閾値を設け、この閾値を超えた時にシークをレポーティングすれば問題ないでしょう。さらに進めて、Savitzky-Golay 法などの手法を駆使して、大量のコンピュータ関連コストをかけることなく、レポーティングされたサンプル値の誤りを処理しても良いでしょう。

一方、ポーリング間隔が一定でない場合は、より一般的な手法を模索せざるを得ません。簡単なのは、最後の timeupdate イベント時から現時点までの動画時間と実時間の差の割合を見ることです。もう少しシンプルに言うと、経過した動画時間を経過した実時間で割るのです。これは基本的に、最後の測定時と現時点の間の動画ポジションの導関数を計算することになります。その際、それ以前に収集した可能性のある情報はすべて無視します。これは他のエンジニアリング分野で良く知られた前進差分と呼ばれる手法です。前進差分は素早く計算できますが、入力シグナルの摂動を増幅することが知られています。割合がゼロに近づくと、大きな問題です。その場合、ほとんどすべての推定値は、求めている実際の信号ではなく入力ノイズとなります。動画の分野では自由が利きます。動画のタイムラインが実際の時間よりもゆっくり進んでいる時間帯は考慮せず、無視したほうがいいのです。

残りのノイズをなくすためには、区分的導関数にこれまでの情報を組み合わせると良いでしょう。私たちが扱っているのは主に線形関数のモデルのため、最小二乗法などの古典的なアルゴリズムを実に簡単に適用できます。しかし、言い訳ではないですが、この手法はおそらく必要以上に複雑になります。これに代わる現実的な手法は、極めて近い時間帯に発生した timeupdate を無視することです。これは測定ミスが増大されるためです。私たちは 1 以下の導関数を無視すると同時に、timeupdate イベントのみを頼りにした確実なシーク探知システムを作り上げました。エンゲージメント トラッキングがフラッシュされると、このシステムが合図を送ります。高い信頼性を持って timeupdate イベントをサポートしていないプラットフォームでも、setTimeout を用いたシミュレーションが可能です。捨てたものではありません。

皆さんが私と同じ立場でしたら、クロス プラットフォームで動画解析レポートをまとめる複雑さに、ショックを受けることでしょう。HTML5、ならびにデスクトップ PC やモバイル デバイスへの動画配信は、世界中の計り知れないほどの人々にオンライン動画の世界を開きました。ただ今だに私たちは、ビデオデッキの正面に配置されたボタンに誘発されたプログラミング モデルと格闘しています。私たちは動画プレーヤ API の「GOTO 文は有害である」以前の日々にいると言っても大げさだとは思いません。私たちには HTML スタンダードの強固な基盤があり、これらの課題を克服する新たなフレームワークを構築する大きな機会にワクワクしています。同期基本命令が一切ない並行プログラミングに関心を持たれた方は、ぜひご協力をお願いします! これがいつの日か「簡単な問題」となることを夢見て。