世界のドキュメンタリー カストロVSゲバラ を見た

NHKオンデマンドにあったので、見た。

自分のカストロ(兄)とゲバラの関係のイメージは学生の頃に見たスティーブン・ソダーバーグ監督の映画のそれだったのだが、そのイメージがぶち壊されるドキュメンタリーだった。

www.nhk-ondemand.jp

キューバ革命からゲバラの死までを、当時の映像や音声、作家やかつてのゲリラ兵のインタビューをまじえながら描く。

カストロの立ち回り方が凄まじく、革命中・直後は「私は共産主義者ではありません、決して!」と言っておきながら、アメリカとの関係がまずくなってソ連と組むしかなくなったら「私はマルクス・レーニン主義者です」とか言ってて、(経済の破綻を避けるにはそうするしかなかったのは分かるが)何だこいつ、という気持ちになった。
普通の指導者ならこんなことを繰り返せば何らかの形で引きずり降ろされると思うのだが、それでも長いこと権力の椅子に座り、今日まで生きながらえているということは、彼のカリスマ・老獪さ・人心掌握の能力は本物なのだろうと思う。

ゲバラは、高潔さ・理想の高さ・順従さをカストロに良いように利用され、用済みになったら追放・半ば見殺しという気の毒な感じだった。ゲバラは、メディアでなにかと神聖化して描かれることが多いが、このドキュメンタリーを見ると中庸なポジションが取れるようになってよいかもしれない(とはいえ、このドキュメンタリーも特定の側面だけを際立てて見せているだけなのかもしれないが)。

チェ ダブルパック (「28歳の革命」&「39歳別れの手紙」) [DVD]

チェ ダブルパック (「28歳の革命」&「39歳別れの手紙」) [DVD]

WebPagetestのAPIを呼んで、結果を保存するスクリプトを書いた

WebPagetestが提供しているREST APIを定期的に呼んで、結果をMongoDBに保存したくなって、スクリプトを書いた。

webpagetest-api を使おうとしたときのメモ - kitak.blogでは、npm packageでインストールしたコマンドからAPIを呼び出したが、職場的にスクリプト言語Pythonが使われることが多いような気がするので、Pythonスクリプトで。
先の記事にも書いたが、WebPagetest - Get API Key で事前にAPIキーを発行しておく。

import os
import time
import requests
from pymongo import MongoClient

client = MongoClient('localhost:27017')
db = client.webpagetest
API_KEY = os.environ["API_KEY"]
target_url = os.environ["TARGET_URL"]
params = {
    "url": target_url,
    "k": API_KEY,
    "f": "json",
    "location": "",
    "mobile": 1,
    "mobileDevice": "Nexus5",
    "video": 1
}
r = requests.get("https://www.webpagetest.org/runtest.php", params=params)
response_json = r.json()

test_id = response_json["data"]["testId"]
result_url = response_json["data"]["jsonUrl"]
print(test_id)
print(result_url)

while True:
    time.sleep(10)
    params = {
        "f": "json",
        "test": test_id
    }
    r = requests.get("https://www.webpagetest.org/testStatus.php", params=params)
    response_json = r.json()
    status_code = int(response_json["statusCode"])
    if status_code == 200:
        r = requests.get(result_url)
        response_json = r.json()
        result = {}
        result['id'] = response_json['data']['id']
        result['summary'] = response_json['data']['summary']
        result['location'] = response_json['data']['location']
        result['from'] = response_json['data']['from']
        result['completed'] = response_json['data']['completed']
        result['average'] = response_json['data']['average']
        db.results.insert_one(result)
        break
    elif status_code >= 400:
        print("ERROR " + target_url)
        break

スクリプトでやっていることは、テストを走らせるAPIを呼び出して、テストが完了したか調べるAPIを10秒毎に呼び出し、テストが完了したら結果から関心のある項目だけ取り出して、MongoDBに格納する、それだけ。 MongoDBを使うと怖い人が来そうな気がするのだが、テスト結果の項目が色々あって、そこから取捨選択したり、構造を変更することを考えるとスキーマレスでカジュアルにバンバン突っ込めるほうが楽。

後はこれを毎日実行して、1~3ヶ月のスパンで数値の変化をみていこうと思っているのだけど、可視化をどうするかが悩ましい。TTFBとかSpeed Indexの推移をみるだけだったら、matplotlabとかでグラフ描けばいいかなぁ...

後、話がズレるのだけど、Pythonスクリプトを書いていて、dictから一部の項目だけ取り出して別のdictを作るのもっと楽に書けないかなぁ、と思った。

JavaScriptでfpsを計測する

Chrome DevToolsにFPS Meterというのがあって、FPSの推移をプロットしてくれるのだけど、他のブラウザや環境によってはプロットできない、あるいは、FPSの値だけ欲しくてプロットは自分でやりたいということもあるので、簡単に計測用のコードを書いてみた。こんなかんじ。

    class FpsCalculator {
      constructor() {
        this._isRunning = false;
        this._beginTime = Date.now();
        this._prevTime = this._beginTime;
        this._frames = 0;
      }
      start() {
        if (this._isRunning) {
          return null;
        }

        this._beginTime = Date.now();
        this._prevTime = this._beginTime;
        this._frames = 0;

        this._isRunning = true;
        const loop = () => {
          if (!this._isRunning) {
            return null;
          }
          this._update();
          requestAnimationFrame(loop);
        }
        loop();
      }
      stop() {
        this._isRunning = false;
        this._frames = 0;
      }
      _update() {
        this._frames++;
        let prevTime = this._prevTime;
        let time = Date.now();

        if (time > prevTime + 1000) {
          console.log((this._frames * 1000) / (time - prevTime));
          this._prevTime = time;
          this._frames = 0;
        }

        this._beginTime = time;
      }
    }
    const calculator = new FpsCalculator();
    calculator.start();

requestAnimationFrameで描画処理の前に呼び出したい関数を登録できる。今回は、描画したフレームの回数をカウントアップして、前回の結果の出力から1秒経過していれば新しい結果を出力するようにしている。描画処理は、理想的には毎秒約60回おこなわれるので(60fps)、requestAnimationFrameに登録し続けている関数も約60回呼ばれて、60に近い数値がConsoleに出力される。JavaScriptでヘビィな処理をおこなったり、リフロー/レイアウトが頻繁に走ったりすると、この回数が少なくなる(fpsが低下する)。

極端なfpsの低下は表示のカクツキ(ジャンク)を引き起こし、ユーザーに違和感を与えるので、原因を特定してそれを取り除く。

ドラマスペシャル・白洲次郎 を観た

マッカーサーを怒鳴りつけたエピソードで有名な白洲次郎のドラマがNHKオンデマンドにあったので観た。
エッセイストだった妻の白洲正子の視点で、白洲次郎西行法師を重ねて描いているのが印象的。

NHKドラマスペシャル 白洲次郎 DVD-BOX

NHKドラマスペシャル 白洲次郎 DVD-BOX

歯の定期健診に行ってきた

三ヶ月に一回いっているやつ。

歯のブラッシングがうまくできているかのチェックと歯石の除去と虫歯になりにくくする何かの塗布。

全体的にきれいにブラッシングできているけれど、上の前歯の側面だったり、下の前歯の裏側(舌を上に動かさないと磨けないやつ)の磨き方が甘いという指摘。次回の検診までは、そこを意識して磨くようにしよう。

hls.js の tsdemuxer.js のコードを読む

個人用メモ。

hls.jsがやっていることをかなり大雑把に書いておくと、JavaScriptでプレイリスト(.m3u8)を取得・パースし、プレイリストに書かれたセグメントファイル(.ts、MPEG2-TS)を取得・パースし、画像と音声のデータ(コーデックは MPEG-4 AVCだったり、MPEG-4 AAC)を取り出して、ごにょごにょした後(ぼかし)にMediaSourceExtensionを使ってvideoタグで再生する、といったかんじ。
JavaScriptで画像・音声データのバイナリをパースしたり操作する処理はヘビィなので、UIスレッドではなく、WebWorkerで別スレッドでおこなうようにしている。
MediaSourceExtensionsが何者か、どういうふうに使うかは、Media Source Extensionsを使ってみた (WebM編) - Qiita が分かりやすい。

今日は、上の「セグメントファイル(.ts、MPEG2-TS)を取得・パースし」のパースの部分を読んでみた。

おもむろにコードを読んでも意味不明なので、デジタル映像の「アーカイブ&デリバリー」に関する技術情報サイト|mpeg.co.jp > VIDEO-ITを取り巻く市場と技術MPEG-2システム - Wikipedia を読んで、簡単にMPEG2-TSがどういったデータ形式になっているか、要素の意味を事前に理解した。(本当はちゃんとした規格のドキュメントを読んだほうがいいんだろうけど、厳密に書かれている分細部に囚われてしまうので、取っ掛かりとしてはこれでいいんじゃないかな...)

セグメントファイルのパースは、 tsdemuxer.js でおこなっている。ひとつの入力(パケットの並び)を複数の出力に分離しているので、demuxer。

セグメントファイルは、188バイト固定長のトランスポートパケットがつながったもの。それぞれのトランスポートパケットに、分割された音声・画像データやプログラム(チャンネル)の情報が含まれている。トランスポートパケットをループで順になめているのが hls.js/tsdemuxer.js at 9ccbc9bc7f629a693fa77863e91d4abd59c1a4da · video-dev/hls.js · GitHub 。次の行で同期ワード( 0x47 )をみて、トランスポートパケットの先頭であるかチェックしている。

トランスポートパケットの識別

PIDは、パケットが扱っているデータが画像か音声かプログラムに関するものか、識別するためのもの( hls.js/tsdemuxer.js at 9ccbc9bc7f629a693fa77863e91d4abd59c1a4da · video-dev/hls.js · GitHub)。

パケットは(おそらく)以下のPAT, PMT, 音声パケット or 画像パケットの順にパースしていく。

PIDが0で固定なのが、PAT。プログラム(チャンネル)の一覧を格納しているもの。hls.jsの場合はひとつで十分なので、parsePAT 関数が返した値を PMT のIDとしている(PMTについては以下で説明)。(hls.js/tsdemuxer.js at 9ccbc9bc7f629a693fa77863e91d4abd59c1a4da · video-dev/hls.js · GitHub)

PMTは、特定のプログラムに含まれる画像や音声それぞれのPIDを格納しているもの。hls.jsでは、それをパースして、画像のPIDは、変数 avcId、音声のPIDは 変数 aacId に代入している。( hls.js/tsdemuxer.js at 9ccbc9bc7f629a693fa77863e91d4abd59c1a4da · video-dev/hls.js · GitHub)

あとは後続のパケットで、PIDが avcId、aacId と一致するか調べて、PES(符号化された画像・音声データを分割してパケット化したやつ)のパースをおこなっている(ぼかし)。

識別に関してはこれくらい。最近、この手のバイナリをパースするJavaScriptのコードを読む機会が多いんですが、大分慣れてきた。次回は、PESのパースまわりを読んでみようと思います。

色々なプロジェクトの utils のコードを読む

最近、時間のあるときに Vue.js や hls.js のソースコードを読んでいるのだけど、この2つのプロジェクトには utils というディレクトリがあって、ロガーやポリフィルのコードが置かれている(utils って名前はどうなんだ、とか、そこに色々置かれているのはどうなんだ、とかそういう話はちょっとスルー)。

これらのプロジェクトに限らず、ある程度大きい規模のプロジェクトは、汎用的な関数がなにかしらの形でまとめられている。これらの関数は大きさも程よく、なにより自分のプロジェクトの参考にもなる。特にコードリーディングしたいものがない場合は、通勤するときとか、土日ベッドでごろごろしているときに普段自分が使っているライブラリの utils のコードを読むと良いんでないかな、と思ったのでした。

(自分は、 hls.js のロガーVue.js のhtmlパーサーを面白く読むことができた)