Skip to content

Commit

Permalink
additional video formats, audio and microphone recording (#9)
Browse files Browse the repository at this point in the history
* support for gif, webm, mp4 and mkv formats
* improved gif encoding
* desktop audio and microphone recording for formats that support audio
* autodetect format from [FILENAME]
* overwrite format through parameter
* overwrite audio and microphone sources through parameters
  • Loading branch information
phisch authored Aug 27, 2020
1 parent e3673b1 commit b0ddda6
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 49 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ $ giph -g 100x200+0+0 -d 5 -t 10
```
Records a 100x200 pixel rectangle in the top left corner of the screen. The recording starts after a 5 seconds countdown and will record for exactly 10 seconds. The resulting gif will be printed to standard output, which makes this able to be piped into other scripts like a file-upload to an image hosting service.


```bash
$ giph -f 30 -t 5 -s -a -m out.webm
```
Records a 5 second video of the users selection at 30 fps. The recording also contains the users desktop audio and microphone. If the recording fails because the default audio source `0` is not the correct one, run `pacmd list-sources` to get the correct source `index` or `name` and pass it to the `-as` parameter instead of using `-a`. Example: `giph -f 30 -t 5 -s -as 1 -m out.webm` (using id) or `giph -f 30 -t 5 -s -as alsa_output.pci-0000_04_00.1.hdmi-stereo.monitor -m out.webm` (using name)

```bash
$ giph -s -t 10 --format webm | curl -F "file=@-" 0x0.st | xclip -selection clipboard
```

Records a 10 second webm of the users selection, uploads the video to 0x0.st using curl and copies the returned url to the clipboard.

## Installation

### Arch
Expand Down
34 changes: 32 additions & 2 deletions man/giph.1
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@ giph \- record gif from desktop, window or selection
[\fB-d\fR \fIINT\fR]
[\fB-t\fR \fIINT\fR]
[\fB-f\fR \fIINT\fR]
[\fB--format\fR \fISTRING\fR]
[\fB-a\fR | \fB -as \fISTRING\fR]
[\fB-m\fR | \fB -ms \fISTRING\fR]
[\fIFILENAME\fR]
.SH DESCRIPTION
.B giph
is a screen recorder that records the desktop, a window or selection and encodes it into a gif file. It prints the encoded gif directly to standard output when omitting [\fIFILENAME\fR].
is a screen recorder that records the desktop, a window or selection and encodes it into a video file.
.br
The recorded video file is encoded in one of the supported formats, gif, webm, mp4 or mkv based on the file extension given in [\fIFILENAME\fR].
.br
When omitting [\fIFILENAME\fR], the default format "gif" is used (use --format to overwrite), and the resulting video directly printed to standard output.
.SH EXAMPLES
.TP
.BI "giph -g " "300x200+600+200 ~/Videos/$(date +%s).png"
Expand Down Expand Up @@ -71,9 +78,32 @@ Sets the time in seconds to wait before the recording starts.
.BR \-t ", " \-\-timer " " \fITIMEDURATION
Sets a fixed time to record. The format is a timeduration as described in the ffmpeg documentation (https://ffmpeg.org/ffmpeg-utils.html#Time-duration). As an example, '10' would mean 10 seconds, '3:30' means 3 minutes and 30 seconds, '1:02:03' means 1 hour, 2 minutes and 3 seconds, and '5.5' means 5.5 seconds.
.TP
.BR \-f ", " \-\-framerate " \fIINT\fR (default: \fI15\fR)"
.BR \-f ", " \-\-framerate " \fIINT\fR (default: \fI20\fR)"
Sets the desired framerate of the recorded gif. A higher framerate will result in a larger filesize.
.TP
.BR \-\-format
Overwrites the format that should be used for the recording. The available formats are
.IR gif ", " webm ", " mp4 " and " mkv "."
While
.IR gif
is the only format that does not support audio recording.
.TP
.BR \-a ", " \-\-audio
Enables audio recording for formats that support audio.
.TP
.BR \-as ", " \-\-audio-source " \fISTRING\fR (default: '\fI0\fR')"
Define which pulseaudio source should be used for the recording. Run `pacmd list-sources` to get a list of all available sources. You can use either the index or the name of the source for this parameter. When setting this parameter, setting
.BR \-a " or " \-\-audio
can be omitted.
.TP
.BR \-m ", " \-\-microphone
Enables microphone recording for formats that support audio.
.TP
.BR \-ms ", " \-\-microphone-source " \fISTRING\fR (default: '\fIdefault\fR')"
Define which pulseaudio source should be used for the recording. Run `pacmd list-sources` to get a list of all available sources. You can use either the index or the name of the source for this parameter. When setting this parameter, setting
.BR \-m " or " \-\-microphone
can be omitted.
.TP
.BR \-y ", " \-\-notify
Uses notify-send to send an urgent notification if an error happens, or a normal notification when the final gif was saved successfully.
.SH SLOP OPTIONS
Expand Down
165 changes: 118 additions & 47 deletions src/giph
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ VERBOSITY=0
# options
SLOP=0
DELAY=0
FRAMERATE=15
FRAMERATE=20
AUDIO=0
AUDIO_SOURCE=0
MICROPHONE=0
MICROPHONE_SOURCE=default
FORMAT_OVERWRITE=""

function print_version() {
echo $VERSION
Expand All @@ -23,21 +28,27 @@ SYNOPSIS
giph [OPTIONS] [FILENAME]
DESCRIPTION
giph is a screen recorder that records the desktop, a window or selection and encodes it into a gif file.
It prints the encoded gif directly to standard output when omitting [FILENAME].
giph is a screen recorder that records the desktop, a window or selection and encodes it into a video file.
The recorded video file is encoded in one of the supported formats, gif, webm, mp4 or mkv based on the file extension given in [FILENAME].
When omitting [FILENAME], the default format "gif" is uded (use --format to overwrite), and the resulting video directly printed to standard output.
OPTIONS
-h, --help Print help and exit.
--version Print version and exit.
-v*, --verbose, --quiet Set the verbosity.
-s, --select Enable slop selection.
-g, --geometry=STRING Record rectangle by geometry. (like 100x300+0+0)
-w, --window=INT Record window by id.
-d, --delay=INT Time in seconds before the recording starts.
-t, --timer=TIMEDURATION Time of the recording. (e.g. 10 for 10 seconds or 1:30 for 1 minute 30 seconds)
-f, --framerate=INT Set the framerate.
-y, --notify Send notification on error or success.
--stop Finish any running giph recordings.
-h, --help Print help and exit.
--version Print version and exit.
-v*, --verbose, --quiet Set the verbosity.
-s, --select Enable slop selection.
-g, --geometry=STRING Record rectangle by geometry. (like 100x300+0+0)
-w, --window=INT Record window by id.
-d, --delay=INT Time in seconds before the recording starts.
-t, --timer=TIMEDURATION Time of the recording. (e.g. 10 for 10 seconds or 1:30 for 1 minute 30 seconds)
-f, --framerate=INT Set the framerate.
--format Set the wanted output format. This overwrites the autodetection.
-a, --audio Enable audio recording.
-as, --audio-source=STRING Overwrite the default audio source.
-m, --microphone Enable microphone recording.
-ms, --microphone-source=STRING Overwrite the default microphone source.
-y, --notify Send notification on error or success.
--stop Finish any running giph recordings.
SLOP OPTIONS
-b, --bordersize=FLOAT Set the selection border thickness.
Expand Down Expand Up @@ -142,6 +153,26 @@ while [[ "$1" == -* ]]; do
shift
FRAMERATE="$1"
;;
--format)
shift
FORMAT_OVERWRITE="$1"
;;
-a|--audio)
AUDIO=1
;;
-as|--audio-source)
shift
AUDIO=1
AUDIO_SOURCE="$1"
;;
-m|--microphone)
MICROPHONE=1
;;
-ms|--microphone-source)
shift
MICROPHONE=1
MICROPHONE_SOURCE="$1"
;;
-y|--notify)
NOTIFY=1
;;
Expand Down Expand Up @@ -188,6 +219,20 @@ done
# set verbosity to -1 if the file should be printed to stdout
[ -n "$1" ] && OUTPUT_FILE=$1 || VERBOSITY=-1

case "$OUTPUT_FILE" in
*.webm) FORMAT="webm" ;;
*.mp4) FORMAT="mp4" ;;
*.mkv) FORMAT="mkv" ;;
*) FORMAT="gif" ;;
esac

if [ -n "$FORMAT_OVERWRITE" ]; then
case "$FORMAT_OVERWRITE" in
webm|mp4|mkv|gif) FORMAT="$FORMAT_OVERWRITE";;
*) log_error "'$FORMAT_OVERWRITE' is not a supported format."
esac
fi

function get_geometry() {
if [ $SLOP = 1 ]; then
log "using slop to determine recording geometry" 1 true
Expand Down Expand Up @@ -299,25 +344,40 @@ function create_temporary_directory() {
log "created temporary directory $TEMP_DIRECTORY" 2 true
}

function start_video_recording() {
ffmpeg=(ffmpeg)
ffmpeg+=(-f x11grab)
ffmpeg+=(-framerate "$FRAMERATE")
ffmpeg+=(-s "$width"x"$height")
ffmpeg+=(-i ":0.0+$x,$y")
ffmpeg+=(-preset ultrafast)
ffmpeg+=(-crf 0)
function record() {
ffmpeg=(ffmpeg -f x11grab -s "$width"x"$height" -i ":0.0+$x,$y")

if [ "$FORMAT" != "gif" ]; then
[ "$AUDIO" = 1 ] && ffmpeg+=(-f pulse -i "$AUDIO_SOURCE")
[ "$MICROPHONE" = 1 ] && ffmpeg+=(-f pulse -i "$MICROPHONE_SOURCE")
[ "$AUDIO" = 1 ] && [ "$MICROPHONE" = 1 ] && ffmpeg+=(-filter_complex amerge -ac 2)
fi

ffmpeg+=(-vf "crop=trunc(iw/2)*2:trunc(ih/2)*2")

[ "$VERBOSITY" -lt "3" ] && ffmpeg+=(-loglevel "quiet")
[ -n "$TIMER" ] && [ "$TIMER" -gt 0 ] && ffmpeg+=(-t "$TIMER")

ffmpeg+=("$TEMP_DIRECTORY/recording.mkv")
ffmpeg+=(-r $FRAMERATE)

case "$FORMAT" in
mp4|mkv)
ffmpeg+=(-pix_fmt yuv420p)
ffmpeg+=(-crf 15)
ffmpeg+=("$TEMP_DIRECTORY/final.$FORMAT")
;;
gif|webm|*)
ffmpeg+=(-preset veryslow)
ffmpeg+=(-crf 0)
ffmpeg+=("$TEMP_DIRECTORY/lossless.mp4")
;;
esac

[ -n "$DELAY" ] && [ "$DELAY" -gt 0 ] && countdown_cli "$DELAY" "recording starts in"

ffmpeg_command=${ffmpeg[*]}
log "ffmpeg command: '$ffmpeg_command'" 2 true

"${ffmpeg[@]}" &
FFMPEG_PID=$!

Expand Down Expand Up @@ -348,37 +408,43 @@ function countdown_cli() {
done
}


function stop_recording_handler_cli() {
log_info "stop recording with \033[1;36mctrl+c\033[0m or call \033[1;36mgiph --stop\033[0m"
trap '' INT
}

function encode() {
log "encoding $FORMAT using ffmpeg" 1 true

function encode_gif_ffmpeg() {
log "encoding gif using ffmpeg encoder" 1 true
ffmpeg_generate_palette=(ffmpeg -i "$TEMP_DIRECTORY/recording.mkv" -vf palettegen "$TEMP_DIRECTORY/palette.png")
[ "$VERBOSITY" -lt "3" ] && ffmpeg_generate_palette+=(-loglevel "quiet")

log "generating color palette from recording" 2 true
"${ffmpeg_generate_palette[@]}"
[ $? = 1 ] && log_error "could not generate color palette from video"

ffmpeg_encode_gif=(ffmpeg -i "$TEMP_DIRECTORY/recording.mkv" -i "$TEMP_DIRECTORY/palette.png" -filter_complex paletteuse -r "$FRAMERATE" "$TEMP_DIRECTORY/encoded.gif")
[ "$VERBOSITY" -lt "3" ] && ffmpeg_encode_gif+=(-loglevel "quiet")

log "encoding gif using recorded video and generated palette" 2 true
"${ffmpeg_encode_gif[@]}"
[ $? = 1 ] && log_error "could not encode gif from video and color palette"
ffmpeg_encode=(ffmpeg -i "$TEMP_DIRECTORY/lossless.mp4")

case "$FORMAT" in
"gif")
ffmpeg_encode+=(-vf "split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse")
;;
"webm")
ffmpeg_encode+=(-c:v libvpx-vp9)
;;
esac

[ "$VERBOSITY" -lt "3" ] && ffmpeg_encode+=(-loglevel "quiet")

ffmpeg_encode+=("$TEMP_DIRECTORY/final.$FORMAT")

ffmpeg_encode_command=${ffmpeg_encode[*]}
log "ffmpeg encode command: '$ffmpeg_encode_command'" 2 true

"${ffmpeg_encode[@]}"
[ $? = 1 ] && log_error "could not encode $FORMAT from lossless recording"
}

function deliver_final_gif() {
function deliver() {
if [ -n "$OUTPUT_FILE" ]; then
mv "$TEMP_DIRECTORY/encoded.gif" "$OUTPUT_FILE" && {
log_success "final gif saved as \"$OUTPUT_FILE\""
mv "$1" "$OUTPUT_FILE" && {
log_success "final $FORMAT saved as \"$OUTPUT_FILE\""
}
else
cat "$TEMP_DIRECTORY/encoded.gif"
cat "$1"
fi
}

Expand All @@ -391,9 +457,14 @@ function delete_temporary_directory() {
function giph() {
get_geometry
create_temporary_directory
start_video_recording
encode_gif_ffmpeg
deliver_final_gif
record

if [[ "$FORMAT" == "gif" || "$FORMAT" == "webm" ]]; then
encode
fi

deliver "$TEMP_DIRECTORY/final.$FORMAT"

delete_temporary_directory
exit 0
}
Expand Down

1 comment on commit b0ddda6

@Deathpfhrot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Phillip du ich bins markus schiller von der wirtschaftsschule kennst mich noch ^^ komm doch mal bitte in Facebook online ich hätte paar fragen zum Programmieren wenn du zeit hast : ) sorry für den post hier

Please sign in to comment.