ByteScope

screenrecord

端末を変える

端末上の MP4 ファイルに画面を録画します。

コマンド
adb shell screenrecord
コマンド
画面と取り込み
リスク
端末を変える

構文

screenrecord [--size <width>x<height>] [--bit-rate <bps>] [--time-limit <seconds>] <device path>

フラグと引数

トークン意味
--time-limit <s>この秒数で停止します。バイナリ自身のヘルプは既定も最大も 180 だと書いています。
--bit-rate <bps>ビット/秒。ヘルプは既定 20 Mbps と書いています。
--size <w>x<h>「要求」であって保証ではありません。ヘルプは、対応していればディスプレイの解像度、していなければ 1280x720 が既定で、エンコーダが対応するサイズを使うよう助言しています。
--bugreport映像にタイムスタンプを含む追加情報を重ねます。何が起きたかだけでなく「いつ」起きたかを示さなければならないクリップのために。
--display-id <id>主ディスプレイではなく物理ディスプレイを 1 つ録ります。有効な id は `dumpsys SurfaceFlinger --display-id` から得られ、いま点いていないディスプレイを名指しすると、ファイルではなく layer stack のエラーが出ます。
--verbose録画しながら進捗を標準出力に報告します。クリップが空で上がってきた最初の 1 回に価値があります。フレームが 1 枚でもエンコーダに届いたかを教えてくれるからです。

使用例

  • screenrecord --time-limit 30 /sdcard/demo.mp4

    30 秒のクリップを撮り、ファイルを取り出します。

  • screenrecord --bit-rate 8000000 --size 720x1560 /sdcard/small.mp4

    バグ報告用に、小さく安価な録画。

  • kill -INT $(pidof screenrecord)

    途中で「正しく」止めます。理由は注意を参照してください。

  • screenrecord --time-limit 0 /sdcard/long.mp4

    上限をまったく設けず、割り込むまで止まりません。Android 14 以降で、13 以前ではゼロは受け付けられる範囲の外なのでコマンドが断ります。

  • dumpsys SurfaceFlinger --display-id

    当てずっぽうで選ぶ前にディスプレイの id を一覧します。id が違うと、引数の誤りではなく layer stack のエラーとして失敗するからです。

出力の読み方

実行中は何も出ず、終わるとファイルが現れます。拒否(エンコーダが受け付けないサイズ、書けないパス)はこのバイナリ自身が印字し、そのテキストこそが答えです。ここで先読みできるものではありません。

出力フィールド

フィールド意味
(no output)録画中。ファイルは進行に合わせて書かれます。
(an error line)端末自身の拒否。そのまま読んでください。
Time limit reached何かに割り込まれたのではなく録画が自分で終わったときに標準出力へ書かれます。ファイルは完全で、索引も付いています。
WARNING: failed at 1440x3120, retrying at 1280x720ディスプレイが報告したサイズをエンコーダが断ったので、録画側が自分で望みを下げて 720p を試しました。これをするのは `--size` を渡さ「なかった」ときだけで、明示のサイズがあるときは、頼んでいないもので代用せずに失敗します。

必要な権限

認可済みの `adb` 接続だけで、他には何も要りません。root も `adb root` も `su` も、USB デバッグを超える開発者向けオプションのスイッチもです。ファイルをどこに置けるかを決めるのは、`adbd` があなたのコマンドを走らせるときの身元です。`adbd` は `shell` の uid と gid に落ち、自分に決まった補助グループの一覧を与えます(`packages/modules/adb/daemon/main.cpp`)。そこには `sdcard_rw`、`ext_data_rw`、`ext_obb_rw` が入っています。`/sdcard/` 以下に書いた録画が何の議論もなく現れるのに、同じコマンドを `/system/` や他のアプリのプライベートディレクトリに向けるとファイルすら作れないのはそのためです。行き先はそれを踏まえて選んでください。`/sdcard/` と `/data/local/tmp/` はどちらも通り、読み取り専用のマウントは通らず、muxer 自身の `open()` が失敗した後のバイナリは説明もせずに `abort()` します。権限の問題と取り違えられがちな拒否が 2 つあって、どちらも権限ではありません。DRM で保護された面が黒く録画されるのは、コンポジタが保護されたバッファをどのエンコーダにも(root 相手でも)渡さないからで、どんな権限もその結末を変えません。そして録画をきれいに止めるには「2 本目の」シェルが要ります。割り込みは既に動いているプロセスに届けなければならないからです。Android Screen Mirror のページがその 2 本目の経路を開いたままにしているのがまさにその理由で、だからあのページの停止ボタンは切り詰められたファイルではなく再生できるファイルを作ります。`adb root` はこのページのどの問題の答えでもありません。製品版のビルドでは問答無用で断られ、`userdebug` と `eng` のイメージで `adbd` を root として起動し直すだけです。

エラーメッセージの読み解き

メッセージ意味
Must specify output file (see --help).引数の解析を抜けたファイル名がなかったので、何も録画されていません。ここのオプションはすべて long option なので、綴りの間違いは高くつきます。`--time-limit` ではなく `--timelimit` と書くと未知のオプションとして飲み込まれ、その後ろの数値も一緒に持って行かれるので、パスはパーサが辿り着かない位置に残ります。ストレージを疑う前にフラグの綴りを確認してください。
Invalid size '1080', must be width x height`--size` は 2 つの辺をリテラルの `x` でつないだものを求め、それ以外は 1 フレームも撮る前に終了コード 2 で断ります。引用符の中に返ってくる値はあなたのシェルが実際に渡したものなので、引用していない空白で後半を失ったサイズはここに前半だけの姿で現れます。引数を引用すれば曖昧さは消えます。
Bit rate 50000bps outside acceptable range [100000,200000000]角括弧の中の組はソースに固定された値で、下限 0.1 Mbps、上限 200 Mbps です。先頭の数値は頼んだ値をそのまま返しています。`--bit-rate` はビット数の直書きに加えて `4M` の略記も受け付け、その略記は「メガビット」なので、`4` と書くのは毎秒 4 ビットを頼むことになり、この行が返ってきます。
Time limit 300s outside acceptable range [1,180]Android 13 以前です。そちらでは 180 秒が既定であるだけでなく硬い上限で、それより長い要求は録画が始まる前に拒否されます。Android 14 と 15 は同じ間違いに対して `[0,4294967295] seconds` という範囲を引用した別の行を印字し、`0` を上限なしとして扱います。つまり 13 の端末で断られたコマンドが、同じ端末を上げた後には通ります。よそで覚えた数値ではなく、端末が引用した範囲を信じてください。
ERROR: INVALID_LAYER_STACK, please check your display state.撮影をディスプレイの layer stack に結び付けられなかったので、中身のないファイルを書く代わりに録画側が終了します。画面が消えているときと、`--display-id` がいま有効でないディスプレイを名指ししているときに見かけます。先に端末を起こすか、`--display-id` を落として主ディスプレイを任せてください。

何が変わるか、そして戻る道

必ずファイルに書き込みます。MP4 は指定した端末上のパスに作られ、すでにあれば上書きされるので、パスを間違えると本物のファイルを置き換えてしまい、元の中身は戻りません。ファイルは録画時間とビットレートに応じて大きくなり、削除するまでストレージを占有します。残したいなら先に `adb pull` でパソコンへ取り出し、そのあと `rm <パス>` で消してください。端末のほかの部分は変わりません。

バージョンとメーカーに関する注意

  • 接続を切るのではなく割り込みシグナルで止めてください。MP4 は索引が書かれて初めて再生でき、このバイナリは割り込みを受けたときの終了処理でそれを書きます。代わりにソケットを落とすと、切り詰められたファイルが残り、プレイヤーによっては何も表示されません。
  • 音声はありません。このバイナリは映像だけを録り、音のフラグもありません。
  • DRM で保護された面は黒く録画されます。スクリーンショットが黒くなるのと同じ理由です。
  • フレームサイズは録画開始時に固定されるので、途中で端末を回すと以降が letterbox になります。
  • 180 秒の上限はケーブルではなくこのバイナリの性質です。ビルドがそれと食い違うなら、どの文書よりも端末自身の拒否を信じてください。
  • 上限こそがリリース間で本当に違う場所です。Android 11、12、13 は `[1,180]` の外を拒否し、Android 14 と 15 は 4294967295 秒まで受け付けて `0` を上限の解除として文書化しつつ、既定は 180 のままです。拒否の行は自分の範囲を引用するので、やる価値のあるバージョン確認はそれだけです。
  • 行き先は、悪いパスが読める形で失敗するようにという理由だけで早い段階に一度開かれ、パスと理由を名指しします。後の muxer 側の open が代わりに失敗すると、メッセージはパスの入っていない素の `ERROR: couldn't open file` になります。だからパスの入っていない失敗は、遅い段階で起きた失敗です。

これには UI があります

Android Screen Mirror はこのコマンドを USB 経由で実行し、返ってきたものを解析します。Chromium 系ブラウザだけで、SDK も不要、どこにもアップロードしません。

Android Screen Mirror を開く

関連コマンド

screenrecord と同じ作業で出てくるコマンド。

コマンド何をするか
screencapスクリーンショットを撮ります。端末上のファイルに書くか、PNG として標準出力に流します。
wm sizeディスプレイの解像度を報告します。上書きすれば、端末は別の画面のふりをします。
rm端末上のファイル、またはディレクトリツリーを削除します。

他の画面と取り込みコマンド

コマンド何をするか
wm densityディスプレイの密度を報告、または上書きします。レイアウトのブレークポイントを実際に動かすのはこちらです。

Web ADB ツール群のパーサを書きながら、AOSP・toybox・カーネルのソースに突き合わせて確認しています。バージョンやメーカーで本当に挙動が変わるところは、世界の半分の端末で間違いになる数値を出す代わりに、そう書いてあります。

よくある質問

adb shell のコマンドはどう実行しますか?

端末で開発者向けオプションと USB デバッグを有効にし、ケーブルを繋いだうえで、platform-tools を入れた機械から adb shell <コマンド> を実行します。adb shell だけを実行すれば対話プロンプトが出て、接頭辞なしで打てます。スクリーンショットのようにバイナリを出力するコマンドでは adb shell ではなく adb exec-out を使ってください。素のシェルサービスは端末を割り当て、それが改行のバイトを書き換えてデータを壊します。

adb shell のコマンドに root は必要ですか?

このリファレンスにあるものには不要です。すべて shell ユーザーとして動き、自分の Android ユーザー向けのパッケージ管理、ほとんどの dumpsys サービスの読み取り、設定プロバイダへの書き込み、入力の注入、共有ストレージの読み取りができます。root が必要なのはこのリファレンスがあえて避けていること、つまり他のアプリのプライベートデータの読み取り(debuggable なビルドに対する run-as を除く)、システムパーティションへの書き込み、/data/anr の直接読み取りです。

自分の端末では出力が違って見えるのはなぜ?

Android のバージョンか、メーカーのどちらかです。一部のフラグやフィールドは特定のリリースから入ったもので、それはコマンドごとに注記しています。残りはメーカーによる改変で、いちばん影響が大きいのは dumpsys です。ダンプはデバッグ出力で、そのテキストはサービスの作者が最後に印字した内容そのもの、しかもメーカーはそれを変えて自分の変更をバックポートします。フィールドは位置ではなく名前で読み、見慣れない形は失敗ではなく差分として扱ってください。

端末ではなくブラウザから実行できますか?

多くのコマンドは可能です。このサイトの Web ADB ツール群は、Chromium 系のデスクトップブラウザから WebUSB で端末と話し、SDK のインストールも不要、どこにもアップロードしません。各ページは、該当するツールがあればそこへリンクしています。知っておく価値のある制限が 2 つあります。ADB インターフェイスを保持できるプログラムは同時に 1 つだけなので、デスクトップの adb server は先に止める必要があります。そして adb forward と adb reverse はブラウザでは一切動きません。

打つより押したい場合は、Web ADB Toolkit がこの種のコマンドをブラウザから USB 経由で実行します。あるいは全コマンドを見る。