web-dev-qa-db-ja.com

GIFスクリーンキャスト。 UNIXの方法

画面の選択した部分の静的スクリーンショットを撮るには、 scrot-s shot.png。これは、StackExchange投稿にイラストを追加するのに最適です。私も this script を見つけて、そのようなスクリーンショットをImgur.comに自動的にアップロードし、Xクリップボードにリンクを配置しました!

これをtwelve に変えましょう:どうすればよいですか同様にGIFスクリーンキャストを作成しますか?

recordmydesktopbyzanz&coなどのareプログラムがあります Ask Ubuntuで説明されているように 「ユーザーフレンドリー」を目指しています「しかし、私の経験では、バグが多く、非効率的で、ほとんどがスクリプト不可能で、このような小さな1回限りのものには適していません。

領域を選択してGIFを記録したいのですが、理解できないコンソールコマンドを使用しています。不可解なスクリプト不可能なGUIの怪物ではありません。

これどうやってするの?

59
Anko

じゃあ

GIF vimcast!

私はffcastを開始し、vimを実行し、ffcastを終了し、次にconverted .avi.gifを終了しました。

別の端末で記録コマンドを実行しました。この回答の最後にある$PATHの洗練されたスクリプト。

どうした?

捕獲

FFcastは、ユーザーがインタラクティブに画面領域を選択し、ジオメトリをFFmpegなどの外部コマンドに渡して画面を記録するのに役立ちます。

ffcastは、Arch Linuxコミュニティでの some hacking (主に lolilolicon )の素晴らしい製品です。あなたはそれを見つけることができます githubで (または AURでArch ersの場合)。依存関係リストはbashffmpegだけですが、インタラクティブな四角形の選択には xrectselAUR link )が必要です。

コマンドの直後にffmpegフラグを追加することもできます。 -r 15を15フレーム/秒でキャプチャするように設定し、-codec:v huffyuvをロスレス録音用に設定します。 (サイズと品質のトレードオフを微調整するには、これらを試してください。)

GIFfing

ImageMagickは.aviビデオを読み取ることができ、品質を維持しながらファイルサイズを大幅に削減するいくつかのGIF最適化トリックがあります。-layers Optimizeからconvertまでは、汎用のオプティマイザを呼び出します。 ImageMagickマニュアルには 高度な最適化に関するページ もあります。

最終スクリプト

これは私の$PATHにあるものです。変換する前に一時ファイルに記録します。

#!/bin/bash
TMP_AVI=$(mktemp /tmp/outXXXXXXXXXX.avi)
ffcast -s % ffmpeg -y -f x11grab -show_region 1 -framerate 15 \
    -video_size %s -i %D+%c -codec:v huffyuv                  \
    -vf crop="iw-mod(iw\\,2):ih-mod(ih\\,2)" $TMP_AVI         \
&& convert -set delay 10 -layers Optimize $TMP_AVI out.gif

最近のffcastの更新後に正しいフラグを特定する際の探偵の仕事に感謝 BenC .

Debianベースのディストリビューションに依存関係をインストールする場合は、 Louis役立つインストールノート を作成しています。

Wheeeeee!

71
Anko

私にとって、答えはffcastffmpegと一緒に使用することでした:

ffcast -w % ffmpeg -f x11grab -show_region 1 -framerate 20 -video_size %s -i %D+%c -codec:v huffyuv -vf crop="iw-mod(iw\\,2):ih-mod(ih\\,2)" out.avi

次に、ffmpegを使用してaviからgifへの変換を行いました。これは非常に高速で、フレームレートをそのまま維持します。

ffmpeg -i out.avi -pix_fmt rgb24 out.gif

最後に @ anko 's answer と同じように変換を使用してgifを最適化しましたが、リソースの使用に制限を設定してconvertの終了を停止しましたkilledメッセージを表示し、ffmpegがすでに処理しているため、遅延を削除しました。

convert -limit memory 1 -limit map 1 -layers Optimize out.gif out_optimised.gif
11
John Hamelink

私のセットアップ(ubuntu 16.04)では、ffcastはgithub上でしばらく更新されていないため、うまく機能しません。

そのため、slop( https://github.com/naelstrof/slop )とffmpegを使用してスクリプトを作成しました。

例:

yay it's working

#!/bin/bash

read -r X Y W H G ID < <(slop -f "%x %y %w %h %g %i")
TMP_AVI=$(mktemp /tmp/outXXXXXXXXXX.avi)

ffmpeg -s "$W"x"$H" -y -f x11grab -i :0.0+$X,$Y -vcodec 
huffyuv -r 25 $TMP_AVI 

convert -set delay 5 -layers Optimize $TMP_AVI out.gif 

更新:コードが更新され、Ruffが述べたようにffmpegがconvertの実行を妨げる終了コード2を返します。記録後、ctrl + Cを押すとffmpegが終了し、convertを実行してout.gifが生成されます。

3
TC Zhang

このリポジトリは、選択領域からgifを作成し、それを最適化するのに役立ちます

https://github.com/devlifeX/record-screen-gif

2
devlief

このため、私はUNIXデスクトップ用のインタラクティブなラッパースクリプトを作成しており、1年間使用した後、そこで共有できてうれしいです。

byzanzgifsiclexdotoolで作成され、スクリプトはphpで記述されています。

出力例:

[1020px、サイズ変更されていないgif幅1020px、70秒、50色、65Kb]

enter image description here

優れた圧縮GIFを提供し、この質問の良いショーケースです。

これはかなり単純なベースであり、ハッキングされる準備ができています。

機能:マウス位置またはフルスクリーンでのGifレコード、サイズ変更、圧縮、色圧縮、逆/マージ、giphy.comカールのアップロード。

10秒のgifレコードを開始するには:gif 10

同じパラメータで複数回記録するには:gif !

フルスクリーンの5秒間のgifレコードを開始するには:gif 5 --fullscreen

スクリプトを実行し、自分自身を心地よく録音:

[45秒、幅645px、フルカラー、976kb]
enter image description here

完全な5kbスクリプト:

#!/usr/bin/php

<?php
#> php xdotool byzanz gifsicle curl
#@ https://webdev23.github.io/gif/gif

echo "Usage: ./gif [time in seconds|!] [--fullscreen|-f]\n";
echo "--------------------------------------------------\n";
echo "Gif recorder tool\n";
echo "gif ! to call back last settings\n";
echo "Please move your mouse at the top left corner point\n";
echo "of the wanted gif area. Then press enter.\n";
echo "\n";

#~ Nico KraZhtest | 05/2017 | https://github.com/webdev23/gif
#~ Create fluid GIF's fastly
#~ You can set the gif record time as argument: ./gif 10
#~ Default record time is 1 seconde, or set it now:
   $recordTime = 1;
#~ ----------------

$t = @$argv[1];

$x1;$y1;$x2;$y2;$gw;$gh;$defc;$rw;

if (!isset($argv[1]) || @$argv[1] === "!") {
  $t = $recordTime;
}

if (@$argv[1] === "!") {
  $pos = file_get_contents("./.config/gif/pos");
  $pos = explode("\n", $pos);
  $x1 = $pos[0];
  $y1 = $pos[1];
  $x2 = $pos[2];
  $y2 = $pos[3];
  $gw = $pos[4];
  $gh = $pos[5];
  $t = $pos[6];
  @$GLOBALS['defc'] = $pos[7];
  @$GLOBALS['$rw'] = $pos[8];
   #~ echo $x1." ".$y1." ".$x2." ".$y2." ".$gw." ".$gh." ".$t." ".$defc." ".@$rw;
  }

else if (@$argv[2] === "fullscreen" || @$argv[2] === "--fullscreen" || @$argv[2] === "-f" || @$argv[2] === "f") {
  echo "############\nStarting fullscreen record\n";
  $fs = system("xdpyinfo  | grep 'dimensions:'");
  echo "\n";
  $fs = explode("    ",$fs);
  echo $fs[1];
  $fs = explode(" ",$fs[1]);
  echo $fs[0];
  $fs = explode("x",$fs[0]);
  echo $fs[0]."\n";
  echo $fs[1];
  $x1 = "0";
  $y1 = "0";
  $x2 = "fs";
  $y2 = "fs";
  $gw = $fs[0];
  $gh = $fs[1];
  $t = $argv[1];
  system("mkdir -p ./.config/gif/");
  system("cd ./.config/gif/ && \
          echo '$x1\n$y1\n$x2\n$y2\n$gw\n$gh\n$t\n\n\n\n' > pos");
  }

else {
  $stdin = fopen('php://stdin', 'r');
  $response = rtrim(fgets(STDIN));

  $p1 = system("xdotool getmouselocation");

  $pos1 = explode(" ",$p1);

  $x1 = $pos1[0];
  $x1 = explode(":",$x1);
  $x1 = $x1[1];
  echo "X1: ".$x1;

  $y1 = $pos1[1];
  $y1 = explode(":",$y1);
  $y1 = $y1[1];
  echo " Y1: ".$y1;

  echo "\nNow move your mousse at the bottom right corner.\nThen enter\n";

  $stdin = fopen('php://stdin', 'r');
  $response = rtrim(fgets(STDIN));

  $p2 = system("xdotool getmouselocation");

  $pos2 = explode(" ",$p2);

  $x2 = $pos2[0];
  $x2 = explode(":",$x2);
  $x2 = $x2[1];
  echo "X2: ".$x2;

  $y2 = $pos2[1];
  $y2 = explode(":",$y2);
  $y2 = $y2[1];
  echo " Y2: ".$y2;

  $gw = ($x2 - $x1);
  echo "\nGif width: ".$gw;

  $gh = ($y2 - $y1);
  echo "\nGif height: ".$gh;
  echo "\n".$x1." ".$y1." ".$x2." ".$y2." ".$gw." ".$gh." ".$t."\n";

  system("mkdir -p ./.config/gif/");
  system("cd ./.config/gif/ && \
          echo '$x1\n$y1\n$x2\n$y2\n$gw\n$gh\n$t\n\n\n\n' > pos");
  }

$unix = date_timestamp_get(date_create());

echo "\n".$unix." | Starting ".$t."s gif record\n";

@system("byzanz-record \
        -v             \
        --duration=$t  \
        --x=$x1        \
        --y=$y1        \
        --width=$gw    \
        --height=$gh   \
        ~/Pictures/gif$unix.gif");

$named = "gif".$unix;

echo "Saved as ~/Pictures/".$named.".gif\n";

echo "\nOptimize | How many colors to keep? (default 100, max 256) \n";

if (@$argv[1] === "!"){
  $pos = file_get_contents("./.config/gif/pos");
  $pos = explode("\n", $pos);
  $defc = $pos[7];
  }

if (!isset($defc)){
  $defc = readline("Colors: ");
  }

if (empty($defc)){
  $defc = "100";
  }

echo "\nKeeping ".$defc." colors\n";

system("gifsicle --verbose -i ~/Pictures/$named.gif -O5 --colors=$defc -o ~/Pictures/$named\_reduced.gif");

echo "\nOptimize | Resize width in pixels (default 360px) \n";

if (@$argv[1] === "!"){
  $pos = file_get_contents("./.config/gif/pos");
  $pos = explode("\n", $pos);
  $rw = $pos[8];
  }

if (!isset($rw)){
  $rw = readline("Width : ");
  }

if (empty($rw)){
  $rw = "360";
  }

echo "\nResized by ".$rw." pixels width\n";

@system("gifsicle --verbose -i ~/Pictures/$named\_reduced.gif --resize-width $rw -o ~/Pictures/".$named."_optimized.gif");

$opt = "~/Pictures/".$named."_optimized.gif";

usleep(5000000);

echo "\nSpecial | Reverse and merge?\n";

system("xdg-open ~/Pictures/".$named."_optimized.gif > /dev/null");

if (@$argv[1] === "!"){
  $pos = file_get_contents("./.config/gif/pos");
  $pos = explode("\n", $pos);
  $rev = $pos[9];
  }

if (!isset($rev)){
  $stdin = fopen('php://stdin', 'r');
  $rev = rtrim(fgets(STDIN));
  $rev = "1";
  }

if (!isset($rev)){
  $rev = "0";
  }

@system("cd ./.config/gif/ && sed -i '8s/.*/$defc/' pos");
@system("cd ./.config/gif/ && sed -i '9s/.*/$rw/' pos");
@system("cd ./.config/gif/ && sed -i '10s/.*/$rev/' pos");

if ($rev === "1"){
  @system("gifsicle                           \
            -i ~/Pictures/$named\_reduced.gif \
            '#-2-1'                           \
            -o ~/Pictures/".$named."_reversed.gif");

  $inv = "~/Pictures/".$named."_reversed.gif";

  usleep(400000);

  @system("gifsicle                           \
            -i ~/Pictures/$named\_reduced.gif \
          --append $inv                       \
          --resize-width $rw                  \
          -o ~/Pictures/".$named."_merged.gif");

  usleep(3000000);

  system("xdg-open ~/Pictures/".$named."_merged.gif > /dev/null");

  }

echo "\n####################";
echo "\nUpload to giphy.com?\n";

$stdin = fopen('php://stdin', 'r');
$response = rtrim(fgets(STDIN));

$m = "~/Pictures/".$named."_merged.gif";
$f = system("du -h $m");
$f = explode("  ",$f);
$f = $f[1];

$www = system('curl                         \
                --progress-bar              \
                -v                          \
                -F "file=@'.$f.'"           \
                -F "api_key=dc6zaTOxFJmzC"  \
                "http://upload.giphy.com/v1/gifs"');

$www = json_decode($www);

echo "\n\nhttps://i.giphy.com/".$www->data->id.".gif\n";

echo "\nThanks YOU!\n";

リバース/マージ機能、芸術的なものを作成します。

オリジナル(435kb)

enter image description here

反転、マージ:(826kb)

enter image description here

phi を使用してインストールするには:

php <(curl https://webdev23.github.io/phi/phi) install https://webdev23.github.io/gif/gif

フルスクリーン:

[1920 * 1080px、gif 400px、50秒、100色、2Mb]

enter image description here

ソース、いくつかの詳しい説明と潜在的なアップデート: https://github.com/webdev23/gif

2
NVRM

TC Zhang の答えの上に構築し(私は単純さが好きでしたが、それを止める方法がわかりませんでした)、gifを [〜#〜] nvrm [〜 #〜] の答え(私が言わなければならない非常に素晴らしい品質)、私は自分のバージョンを作成しました。

まず、録音する領域を(無音で)要求し、次にボタンの付いた小さなボックスを選択の右下隅のすぐ下に配置します(録音に干渉しません。上部に残りますが、フォーカスを取得しません。

いつでも一時停止/続行、または単に停止することができます。事前に期間を指定するのは面倒だと思いますので、お気軽に!

結果は〜/ Downloads /に配置され、2020-02-29--0237.gifのようなタイムスタンプが付けられます(保存場所/保存方法の指定に時間をかけたくない)。

必要に応じて自由にカスタマイズしてください。私はそれをとても自明にしようとしました。

私はそれをすべて一緒にまとめることを学びました(yad、ffmpeg、シグナル、bashなど)

誰かが録音/変換品質のより良いパラメータを見つけたら、私に知らせてください。更新させていただきます。

よろしくお願いします。

例:

enter image description here

#!/bin/bash

# Inspired on script from https://unix.stackexchange.com/questions/113695/gif-screencasting-the-unix-way

# Failsafe, just in case interactive stop fails, recording can be large
# If you are goint to pause consider increasing it as clock is still ticking while paused
DURATION=40;

# Destination for output gif file
GIF_OUT_FOLDER="/home/$USER/Downloads"
GIF_OUT_FILE=$GIF_OUT_FOLDER/$(date  +'%Y-%m-%d--%H%M').gif

# Request section to record interactively
read -r X Y W H G ID < <(slop -f "%x %y %w %h %g %i")

# Create the name for the temp file with video
TMP_AVI=$(mktemp /tmp/outXXXXXXXXXX.avi)

# Export variables
export TMP_AVI DURATION GIF_OUT_FOLDER GIF_OUT_FILE X Y W H G ID

# Define functions and export them
#--------------------------------------------
stop_recording_and_create_gif() {
killall --user $USER  --ignore-case  --signal INT  ffmpeg ; convert  -layers removeDups -layers Optimize -delay 13 -loop 0 $TMP_AVI  $GIF_OUT_FILE && rm -I "$TMP_AVI";
# Optimize gif file
gifsicle --verbose --batch --interlace $GIF_OUT_FILE --optimize=05 --colors=128; # --output  out.gif
}
export -f stop_recording_and_create_gif
#--------------------------------------------
start_recording_screen_section () {
# Record and convert to gif file
#3 not-original / added -t n   for n seconds recording
ffmpeg -t $DURATION -s "$W"x"$H" -y -f x11grab -i :0.0+$X,$Y -vcodec huffyuv -r 25 $TMP_AVI;
}
export -f start_recording_screen_section
#--------------------------------------------
FContinue () { killall --user $USER  --ignore-case  --signal SIGCONT ffmpeg ;}
FPause () { killall --user $USER  --ignore-case  --signal SIGSTOP ffmpeg ; }

export -f FContinue FPause
####################################

# Collect the YAD options
cmd=(yad 
    --width 5
    --height 5
    --on-top
    --skip-taskbar
    --borders=0
    #--undecorated  (so you have something to grab it if you want to move it)
    --columns 1
    --no-focus
    #--mouse (it gets a bit inside the recording window)
    --geometry=5x5+$(($X+$W+10))+$(($Y+$H+10))
    #--no-buttons  (avoids having buttons we don't need)
    # This is a trick to have the buttons vertical
    --form  
    --title="Screencast to GIF"
    --field='Start recording!stop!Start recording (maximum defined duration)':fbtn 'bash -c "start_recording_screen_section"'
    --field='Stop recording!gtk-quit!Stop recording and create gif file in output folder':fbtn 'bash -c "stop_recording_and_create_gif & kill -SIGUSR1 $YAD_PID"'
    --field='Pause!gtk-pause!':fbtn 'bash -c "FPause"'
    --field='Continue!gtk-continue!':fbtn 'bash -c "FContinue"'
    --button='Quit!gtk-ok':'bash -c "kill -SIGUSR1 $YAD_PID"'
)
# Run yad
"${cmd[@]}"

# Cleanup before leaving
unset TMP_AVI DURATION GIF_OUT_FOLDER GIF_OUT_FILE X Y W H G ID
unset stop_recording_and_create_gif
unset start_recording_screen_section
unset FContinue FPause
1
Rub