標籤:comment 目的 boot ddc bug 產生 調用 豎屏 .net
目的
編寫 bash 指令碼, 實現一行命令得到 Android 手機錄製螢幕 gif 動圖檔案.
博主使用 ubuntu 系統, shell 為 bash. 這個指令碼也可以用在 mac 系統上.
聽說 windows 系統出了 ubuntu on windows, 不知道能不能使用這個指令碼.
原理adb shell screenrecord
Android 4.4 版本後系統內預置了一個 screenrecord 命令, 可以用來將螢幕錄製為 MP4 格式. 具體命令格式可以通過 –help 參數查看:
$ adb shell screenrecord --helpUsage: screenrecord [options] <filename>Android screenrecord v1.2. Records the device‘s display to a .mp4 file.Options:--size WIDTHxHEIGHT Set the video size, e.g. "1280x720". Default is the device‘s main display resolution (if supported), 1280x720 if not. For best results, use a size supported by the AVC encoder.--bit-rate RATE Set the video bit rate, in bits per second. Value may be specified as bits or megabits, e.g. ‘4000000‘ is equivalent to ‘4M‘. Default 4Mbps.--bugreport Add additional information, such as a timestamp overlay, that is helpful in videos captured to illustrate bugs.--time-limit TIME Set the maximum recording time, in seconds. Default / maximum is 180.--verbose Display interesting information on stdout.--help Show this message.Recording continues until Ctrl-C is hit or the time limit is reached.
舉例:
adb shell screenrecord --size "360x640" --bit-rate 2000000 /sdcard/android_screenrecord_test.mp4
上面的命令將把所串連的手機螢幕錄製為 寬高 360x640, 位元速率 2M 的視頻, 儲存為手機 sd 卡根目錄下的 android_screenrecord_test.mp4 檔案.
該命令會持續錄製, 直到用 ctrl-c 終止命令, 那麼錄製也就結束了.
也可以用 –time-limit TIME 參數來預先指定錄製時間長度, 到時間會自動結束. 預設的最大時間長度為 3 分鐘.
ffmpeg
使用 ffmpeg 抽幀的命令將視頻提取為一系列圖片:
ffmpeg -i video.mp4 -r 5 ‘frames/frame-%03d.jpg‘
其中: -r 5 代表抽取的幀率, 即每秒視頻抽取 5 幀出來.
convert
使用 imagemagick 包中的 convert 命令將一系列圖片組合為 gif 動圖格式:
convert -delay 20 -loop 0 *.jpg myimage.gif
其中: -delay 20 代表所產生的 gif 動圖每幀之間的時間間隔, 即每 0.2 秒顯示下一幀.
如果系統內還沒有 convert 命令, 可以用如下命令安裝:
sudo apt-get install imagemagick
博主使用 ubuntu 16.10, 這個命令是預置在系統裡的, 不需要安裝.
ffmpeg 及 convert 參數設定
上面兩個命令中, ffmpeg -r 5 和 convert -delay 20 這兩個參數值, 分別是 視頻抽幀間隔 和 gif每幀間隔, 假設其分別為 video_fps 和 gif_delay, 那麼這兩個參數在設定時必須滿足如下條件:
video_fps * gif_delay = 100
如果乘積小於 100, 則產生的 gif 會比原本的播放速度快;
如果乘積大於 100, 則產生的 gif 會比原本的播放速度慢.
至於原因, 結合上面對這兩個參數的介紹, 思考一下就明白了.
捕獲錄製結束事件
上面三個命令分開調用, 實現錄屏為 gif 已經相當簡單了.
如果要將三條命令寫在一個指令碼裡, 在一個過程中完成功能, 第一個要解決的是如何捕獲錄製結束事件, 即 ctrl-c 命令.
在 bash 中可以通過下面指令碼實現:
# catch ctrl-c signalCTRL_C() { # ctrl-c hit, do something}trap CTRL_C SIGINT
有了這個方法擷取錄製結束事件, 再往下就簡單了.
這裡遇到一個坑, 就是如果捕獲 ctrl-c 後直接開始轉換 gif 的操作, 會失敗. 試過幾次後, 發現是 ctrl-c 後其實 Android 的 screenrecord 命令並沒有處理完, 這時候的視頻還不可用. 解決的辦法簡單粗暴, 讓指令碼原地 sleep 2秒, 再去操作所產生的 MP4 檔案就可用了.
最終指令碼
也不知道該寫些啥了, 直接貼出完整指令碼吧:
#!/bin/bash# author : [email protected]#========================================================# define param group hereQUALITY_1=("360x640" 1000000 4 25)QUALITY_2=("360x640" 1000000 5 20)QUALITY_3=("360x640" 1000000 10 10)QUALITY_4=("720x1280" 1000000 4 25)QUALITY_5=("720x1280" 1000000 5 20)#========================================================QUALITY=(${QUALITY_2[@]})RESOLUTION=${QUALITY[0]}BIT_RATE=${QUALITY[1]}GIF_FPS=${QUALITY[2]}GIF_DELAY=${QUALITY[3]}# GIF_FPS and GIF_DELAY must meet the following condition:# GIF_FPS * GIF_DELAY = 100OUTPUT_FILE_NAME=android_screen_record.$(date +%m%d%H%M%S).gifOUTPUT_FILE_DIR=$(pwd)OUTPUT_VIDEO_NAME=screenrecord_$(date +%m%d%H%M%S).mp4OUTPUT_VIDEO_DEVICE_DIR=/sdcardTMP_DIR=/tmp/android_screen_to_gif_$(date +%m%d%H%M%S)RECORDING=true# you may use adb by absolute file path. if so, specify it hereADB="adb"#========================================================# catch ctrl-c signalCTRL_C() { if $RECORDING; then echo "stop recording. start convert..." RECORDING=false else # ctrl-c hit but not for stop recording, just exit. exit $? fi # adb screenrecord may still deal with mp4 file creating, # just wait for it a little while. sleep 2s adb pull $OUTPUT_VIDEO_DEVICE_DIR/$OUTPUT_VIDEO_NAME $TMP_DIR if [ -f $TMP_DIR/$OUTPUT_VIDEO_NAME ]; then # remove video on phone adb shell rm $OUTPUT_VIDEO_DEVICE_DIR/$OUTPUT_VIDEO_NAME echo "converting file: $TMP_DIR/$OUTPUT_VIDEO_NAME" MP4ToGIF $TMP_DIR/$OUTPUT_VIDEO_NAME else echo "* create screen record mp4 fail" exit 2 fi}trap CTRL_C SIGINT# catch script exit eventCLEAR_WORK() { if [ -e $TMP_DIR ]; then # since the tmp files have been put into /tmp/ dir, they will get # removed on system reboot. thus we are in no hurry to remove them now. # un-commit this line if you want to remove tmp files immediately after script run #rm $TMP_DIR echo fi}trap "CLEAR_WORK" EXIT#========================================================function MP4ToGIF() { echo "*** extract frames ***" mkdir $TMP_DIR/frames ffmpeg -i $1 -r $GIF_FPS "$TMP_DIR/frames/frame-%03d.jpg" echo "*** convert frames to gif ***" convert -delay $GIF_DELAY -loop 0 "$TMP_DIR/frames/*.jpg" $OUTPUT_FILE_DIR/$OUTPUT_FILE_NAME}#========================================================if [ ! -d "$OUTPUT_FILE_DIR" ]; then echo "* output dir not exists: $OUTPUT_FILE_DIR" exit 1fiif [ ! -e $TMP_DIR ]; then mkdir $TMP_DIRfiif [ ! -e $TMP_DIR ]; then echo "* tmp dir not exists: $TMP_DIR" exit 1fiecho "params: $RESOLUTION, $BIT_RATE, $GIF_FPS, $GIF_DELAY"adb shell screenrecord --verbose --size $RESOLUTION --bit-rate $BIT_RATE $OUTPUT_VIDEO_DEVICE_DIR/$OUTPUT_VIDEO_NAME
開頭定義的那幾個數組, 是為了便於測試. 最終產生的 gif 檔案也直接儲存在了目前的目錄下.
主要是因為加上參數化, 代碼會多很多, 就不容易找到主要功能了.
帶參數化, 帶簡易協助文檔的完整指令碼, 可以在下面連結中找到:
android_screen2gif.sh
使用
使用前提:
- adb 可以正常串連到手機, 就是不能有 offline 之類的問題. (這裡安利另一篇文章: 解決 ubuntu adb 裝置識別問題)
- 手機必須是 4.4 以上系統.
指令碼本身就是為了使用簡單寫的. 只需在命令列直接執行指令碼, 即可開始手機螢幕錄製. 因為是測試, 選在 /tmp 目錄操作.
$ cd /tmp/$ android_screen2gif.sh params: 360x640, 1000000, 5, 20Main display is 720x1280 @60.00fps (orientation=0)Configuring recorder for 360x640 video/avc at 1.00MbpsContent area is 360x640 at offset x=0 y=0
這時錄製進行中, 命令列掛起. 等你認為錄製可以結束了, 按下 ctrl-c, 錄製結束, 開始轉換 gif 的步驟. 一般需要3到4秒, 錄屏的 gif 就在目前的目錄產生了.
^Cstop recording. start convert...[100%] /sdcard/screenrecord_0407090859.mp4converting file: /tmp/android_screen_to_gif_0407090859/screenrecord_0407090859.mp4*** extract frames ***ffmpeg version 3.0.7-0ubuntu0.16.10.1 Copyright (c) 2000-2017 the FFmpeg developers......Input #0, mov,mp4,m4a,3gp,3g2,mj2, from ‘/tmp/android_screen_to_gif_0407090859/screenrecord_0407090859.mp4‘:......Output #0, image2, to ‘/tmp/android_screen_to_gif_0407090859/frames/frame-%03d.jpg‘:......*** convert frames to gif ***result gif file:/tmp/android_screen_record.0407090859.gif
這一步輸出較多, 用 ...... 代替了部分輸出. 最後那行就是最終產生的 gif 錄屏檔案了.
參數建議
根據自測 及 最終 gif 產生的過程, 可以得到如下結論:
視頻解析度參數:
寬高越大越清晰, 最終產生的 gif 檔案越大. 這個是很明顯的.
最好按手機豎屏顯示的方式, 將解析度設定為 9:16 的比例. 如果設定為其他比例, 比如 480:480, 則錄製出的視頻會有很寬的黑邊.
視頻位元速率參數:
先說結論: 位元速率設定基本不會影響最終產生的 gif 檔案品質.
因為最終 gif 檔案來自視頻抽幀, 視頻位元速率的大小對於比如每秒抽取10幀這樣的需求, 對抽取出的圖片清晰度影響不大. 因此為了中間檔案更小, 建議把這個參數設低即可.
抽幀幀率 及 每幀間隔:
這兩個參數對最終 gif 品質影響很大. 其中:
抽幀幀率越大, 最終 gif 品質越高;
每幀間隔越小, 最終 gif 品質越高.
如前述, 這兩個參數必須成對設定. 如果這兩個參數都取整數的話, 基本上可以設定的就下面這幾對:
2, 504, 255, 2010, 10
其中:
10, 10 這組, 設定每秒10幀, gif 每幀間隔 0.1 秒, 這樣5秒的gif檔案就要大概 10M 大小了.
2, 50 這組, 設定每秒2幀, gif 每幀間隔 0.5 秒, 最終gif檔案卡頓就很嚴重了.
因此建議選取 5, 20 這組參數. 如果對gif品質要求很高, 可以試試 10, 10 這組參數.
綜上, 小夥伴們可以自己嘗試下設定不同的參數組合, 試幾次就能體會該怎麼設定了.
參考:
create gif from mp4 via command line
command convert doc
再次無恥的安利安利自己的指令碼項目:
android_screen2gif.sh
一鍵產生 Android 錄屏 gif 的指令碼