From 4e6a1532e7fc3c2652cd7ca6d9ec30b9ea720593 Mon Sep 17 00:00:00 2001 From: Daniel Bermond Date: Sun, 12 Feb 2017 20:34:18 -0200 Subject: [PATCH] Initial commit --- COPYING | 339 ++++++++++++ README.md | 285 ++++++++++ screencast | 1499 ++++++++++++++++++++++++++++++++++++++++++++++++++ screencast.1 | 366 ++++++++++++ 4 files changed, 2489 insertions(+) create mode 100644 COPYING create mode 100644 README.md create mode 100755 screencast create mode 100644 screencast.1 diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..dbb7fbb --- /dev/null +++ b/README.md @@ -0,0 +1,285 @@ +screencast +========== + +- [DESCRIPTION](#description) +- [USAGE](#usage) +- [OPTIONS](#options) + - [```-o, --output-dir=DIR```](#-o---output-dirdir) + - [```-t, --tmp-dir=DIR```](#-t---tmp-dirdir) + - [```-u, --auto-filename```](#-u---auto-filename) + - [```-p, --position=N,N```](#-p---positionnn) + - [```-s, --size=NxN```](#-s---sizenxn) + - [```-r, --fps=N```](#-r---fpsn) + - [```-f, --format=TYPE```](#-f---formattype) + - [```-i, --audio-input=NAME```](#-i---audio-inputname) + - [```-a, --audio-encoder=NAME```](#-a---audio-encodername) + - [```-v, --video-encoder=NAME```](#-v---video-encodername) + - [```-e, --fade=TYPE```](#-e---fadetype) + - [```-m, --volume-factor=N```](#-m---volume-factorn) + - [```-w, --watermark=TEXT```](#-w---watermarktext) + - [```-k, --wmark-position=N,N```](#-k---wmark-positionnn) + - [```-z, --wmark-size=NxN```](#-z---wmark-sizenxn) + - [```-c, --wmark-font=NAME```](#-c---wmark-fontname) + - [```-x, --fixed=N```](#-x---fixedn) + - [```-n, --no-notifications```](#-n---no-notifications) + - [```-g, --png-optimizer=NAME```](#-g---png-optimizername) + - [```-l, --list```](#-l---list) + - [```-h, --help```](#-h---help) +- [EXAMPLES](#examples) +- [INSTALLATION](#installation) +- [REQUIREMENTS](#requirements) +- [REMARKS](#remarks) +- [LINKS](#links) +- [AUTHOR](#author) +- [COPYRIGHT](#copyright) +- [LICENSE](#license) + +------------------------------------------------------------------------ + +## DESCRIPTION +**screencast** is a command line interface to record a X11 desktop using FFmpeg. It’s designed to make desktop recording a simple task, eliminating the somewhat complex FFmpeg command line arguments and the need of multiple commands. It uses predefined encoder settings that should be suitable for most needs. The default settings provides a quick and affordable way to record the desktop, letting the user to be focused on just specifying the desired video position and size. If the user doesn’t want to stick with the default settings it is possible to choose among a set of supported encoders and container formats. + +**screencast** not only provides an easy way to record your desktop, but it also has options to automatically add some effects to the recordings, like video fade-in / fade-out, text watermarking and volume increase. + +## USAGE +``` +$ screencast [options] output +$ screencast [options] -u +``` + +The specified output filename must have an extension which in turn must be a supported container format. + +## OPTIONS +Long options can be used with spaces or an equal sign (’```=```’). For example, ```--fade in``` is the same as ```--fade=in```. + +#### ```-o, --output-dir=DIR``` + +Set the output video to be saved in *DIR*. This is to be used with ```-u``` option (if you want to specify a save directory when using automatic output filename choosing). When not using ```-u``` option you can specify the output directory directly in the output filename. + +default: the local directory + +#### ```-t, --tmp-dir=DIR``` + +Set temporary files to be placed in *DIR*. By default, the ```/tmp``` directory will be used for temporary files, which usually is a ramdisk filesystem in most systems. You may want to change it if you have limited RAM and/or are recording very long videos. Make sure to have enough free space in the specified directory. + +default: ```/tmp``` + +#### ```-u, --auto-filename``` + +Auto choose output filename based on date and time. The output filename will have the following format: + +screencast-YEAR-MONTH-DAY\_HOUR.MINUTE.SECOND.FORMAT + +#### ```-p, --position=N,N``` + +The screen position defining from where the recording will take place. These are X and Y offsets from the screen top left corner. Combined with ```-s``` option it will define a rectangular desktop area that will be recorded. + +default: ```0,0``` (screen top left corner) + +#### ```-s, --size=NxN``` + +The video size. This is actually the video resolution. Combined with ```-p``` option it will define a rectangular desktop area that will be recorded. + +default: ```640x480``` + +#### ```-r, --fps=N``` + +Video framerate (frames per second - fps). + +default: ```25``` + +#### ```-f, --format=TYPE``` + +Container format of the output video. This is to be used with ```-u``` option (if you want to specify a container format when using automatic output filename choosing). When not using ```-u``` option you can specify the container format directly in the output filename. + +default: ```mp4``` + +supported types: ```mp4```, ```mkv```, ```webm```, ```ogg``` + +#### ```-i, --audio-input=NAME``` + +ALSA audio input device. When setted to ```none``` the audio will be disabled (video without audio, only video stream will be present). To determine possible audio input device names please see the +[FFmpeg ALSA capture guide](https://trac.ffmpeg.org/wiki/Capture/ALSA). + +default: ```pulse``` + +#### ```-a, --audio-encoder=NAME``` + +Audio encoder to be used to encode the recorded audio. When setted to ```none``` the audio will be disabled (video without audio, only video stream will be present). + +default: ```aac``` + +supported types: ```aac```, ```opus```, ```vorbis```, ```mp3```/```mp3lame```, ```shine```, ```none``` + +#### ```-v, --video-encoder=NAME``` + +Video encoder to be used to encode the recorded video. If using a NVIDIA hardware accelerated encoder please make sure that you have a NVIDIA graphics card that supports the choosed encoder. + +default: ```x264``` + +supported types: ```x264```, ```h264_nvenc```, ```x265```, ```kvazaar```, ```hevc_nvenc```, ```theora```, ```vp8```, ```vp9``` + +#### ```-e, --fade=TYPE``` + +Video fade effect to be added to the recorded video. When setted to ```none``` the recorded video will have no fade effect. + +default: ```none``` + +supported types: ```in```, ```out```, ```both```, ```none``` + +#### ```-m, --volume-factor=N``` + +Volume increase effect factor. This will increase the volume of the recorded audio. Normally, audio volume is low with default settings, even if you increse your microphone capture volume. Use this to give your videos a better hearing experience, letting your viewers fell more confortable to watch it whithout needing to rise their sound volume. It works as a percentage factor. For example, a value of ```1.5``` will increase volume by 50% and a value of ```2.0``` will double volume. When setted to ```1.0``` or ```0.0``` this effect is disabled. + +default: ```1.0``` + +#### ```-w, --watermark=TEXT``` + +Enable text watermarking, setting text to *TEXT*. Although it is a text, it is generated as a PNG image so it can be integrated in the video. + +default: disabled + +#### ```-k, --wmark-position=N,N``` + +Set text watermark position inside the video. These are X and Y offsets from the video top left corner (not from the screen). Combined with ```-z``` option it will define a rectangular area in the video that will contain the text watermark image. + +default: ```970,10``` (video top right corner) + +#### ```-z, --wmark-size=NxN``` + +Set text watermark size. Combined with ```-k``` option it will define a rectangular area in the video that will contain the text watermark image. + +default: ```255x35``` + +#### ```-c, --wmark-font=NAME``` + +Set text watermark font to *NAME*. + +default: ```Arial``` + +note: if the default or setted font is not installed it will be auto choosed + +#### ```-x, --fixed=N``` + +Set the video to have a fixed length of *N* seconds. When setted to ```0``` this is disabled, meaning a indefinite video length that will be recorded until the user stops it by presing the **q** key in the terminal window. + +default: ```0``` + +#### ```-n, --no-notifications``` + +Disable desktop notifications. Desktop notifications are shown by default, allowing a better visual control of the recording. Use this option to disable them. + +#### ```-g, --png-optimizer=NAME``` + +Use PNG optimizer *NAME* and *advdef* (advancecomp) in the PNG image generated by ```-w``` option that will be used as a text watermark. This option is useful when you want to use a big text watermark in a big video, allowing the video to be a few bytes smaller. Not really needed if using default watermark settings with a small text. When setted to ```none``` PNG optimization is disabled. + +default: ```none``` + +supported ones: ```truepng```, ```pingo```, ```optipng```, ```opt-png```, ```none``` + +#### ```-l, --list``` + +List arguments supported by these options. + +#### ```-h, --help``` + +Help screen. + +## EXAMPLES +- Use all default settings: + + - ```$ screencast myvideo.mp4``` + +- Use default settings for a 1280x720 video from screen positon 200,234 with auto choosen output filename: + + - ```$ screencast -p 200,234 -s 1280x720 -u``` + +- Changing just the container format without specifying encoders will make it to auto choose them. In this case, the ```webm``` format will produce a video with opus and vp9 encoders: + + - ```$ screencast /home/user/webmvideos/myvideo.webm``` + +- Specifying save dir and container format, with auto choosen encoders and output filename. In this case, the ```ogg``` format will produce a video with vorbis (libvorbis) and theora encoders: + + - ```$ screencast -o /home/user/myvideos -f ogg -u``` + +- 1280x720 video from screen positon 200,234 , 30 fps, mp3 (libmp3lame) audio encoder, x265 video encoder, mkv container format, fade-in video effect, volume increase effect of 50%, small text watermark in top right video corner: + + - ```$ screencast -p 200,234 -s 1280x720 -r 30 -a mp3 -v x265 -e in -m 1.5 -w www.mysitehere.com myvideo.mkv``` + +**NOTE**: +When not using the ```-x``` option press the **q** key in terminal window to end the recording. + +## INSTALLATION +Make the **screencast** file executable and copy it to a directory that is in your *PATH*. + +Copy the *screencast.1* man page file to your user commands man page directory, usually at ```/usr/share/man/man1```. For convenience, firstly compress the man page with *gzip*. + +You can acomplish this by doing: + +``` +$ chmod +x screencast +$ sudo mv screencast /usr/local/bin +$ gzip -9 screencast.1 +$ sudo mv screencast.1.gz /usr/share/man/man1 +``` + +## REQUIREMENTS +- The minimum requirement is a recent *FFmpeg* version compiled with support for x11grab and the desired encoders. For example, if you want to use *vp9* video encoder and *opus* audio encoder it will require *FFmpeg* to be compiled with support for x11grab, libvpx and libopus. It’s advised to use *FFmpeg* version git master. You can see a *FFmpeg* compilation guide and a recommended *FFmpeg* Arch Linux AUR package at the [LINKS](#links) section. + +- When recording audio (```-i``` and ```-a``` options not setted to ```none```) *FFmpeg* must have been compiled with support for ALSA audio. The default ```pulse``` setting for ```-i``` option requires *FFmpeg* to be compiled with support for pulseaudio (libpulse) as well. + +- *notify-send* (libnotify) is needed for desktop notifications. Note that desktop notifications are enabled by default. They can be disabled by using the ```-n``` option, eliminating the need of *notify-send*. Running **screencast** in a system without *notify-send* and without using the ```-n``` option will result in error. + +- Other requirements are needed according to additional options that may be specified by the user: + + - *FFprobe* and *bc* are needed for video fade effect (```-e``` option). + + - *ImageMagick* is needed for text watermarking (```-w``` option). Both IM6 and IM7 are supported, but IM7 is preferred. + + - At least one supported PNG optimizer and *advdef* (advancecomp) are needed for PNG (watermark) optimization (```-g``` option). + +## REMARKS +- **screencast** uses a two step recording process. Firstly the audio and video are recorded to a lossless format and at a second stage it is encoded to produce the output video. That’s why you see a desktop notification saying ’*encoding...*’. This mechanism allows a better video and avoids problems. + +- When using ```aac``` audio encoder (which is the default setting), **screencast** will check if the detected FFmpeg build has support for libfdk\_aac and use it if present, otherwise it will use the FFmpeg built-in AAC audio encoder. Make sure to have a recent FFmpeg version as older versions do not support the built-in AAC audio encoder without being experimental, or do not support it at all. + +- FFmpeg encoder names have the 'lib' prefix removed for simplicity. For example, libx264 is called ```x264``` in this program. + +- Although the ```vorbis``` audio encoder is mentioned in the options, it is made this way just for simplicity as mentioned right above. When the user selects the ```vorbis``` audio encoder **screencast** uses the FFmpeg libvorbis encoder, which has a much superior quality than the FFmpeg built-in vorbis encoder. + +- The ```mkv``` container format is the only one that supports all audio and video encoders. All other container formats have restrictions. **screencast** will exit with error if an unsupported encoder is choosed for a given container format. For example, you cannot use the ```opus``` audio encoder with ```mp4``` container format. + +- When using the ```mp4``` container format, the moov atom will be automatically moved to the beginning of the output video file. This is the same as running *qt-faststart* in the output video and is useful for uploading it to streaming websites like [YouTube](https://www.youtube.com/). + +- The default settings for container format and audio/video encoders will produce a video that is ready to be uploaded to [YouTube](https://www.youtube.com/). + +- The default ```pulse``` audio input setting (```-i``` option) will be suitable for most users as it will use the default recording device configured in pulseaudio, as long as FFmpeg was compiled with ALSA and pulseaudio support. + +- *Oxygen* icon names are used for displaying desktop notifications. Although not a requirement, *Oxygen* icons are recommended to be installed for a better visual integration. + +- **screencast** will try to play a notification sound when the encoding process is finished. For this, it will use *paplay* (from *pulseaudio*) and a sound file from the freedesktop sound theme (usually a package called *sound-theme-freedesktop* in most Linux distributions). Although not a requirement, they are recommended to be installed for a better user experience. + +## LINKS +- FFmpeg: [https://www.ffmpeg.org/](https://www.ffmpeg.org/) + +- FFmpeg compilation guide: [https://trac.ffmpeg.org/wiki/CompilationGuide](https://trac.ffmpeg.org/wiki/CompilationGuide) + +- **screencast** Arch Linux AUR package: [https://aur.archlinux.org/packages/screencast/](https://aur.archlinux.org/packages/screencast/) + +- FFmpeg version git master Arch Linux AUR package (with all possible libs including libfdk_aac): [https://aur.archlinux.org/packages/ffmpeg-full-git/](https://aur.archlinux.org/packages/ffmpeg-full-git/) + +## AUTHOR +Daniel Bermond + +[https://github.com/bermond/screencast](https://github.com/bermond/screencast) + +## COPYRIGHT +Copyright © 2015-2017 Daniel Bermond + +## LICENSE +GNU General Public License version 2 (GPL2). + +For details see the file COPYING or visit: +[http://www.gnu.org/licenses/gpl-2.0.html](http://www.gnu.org/licenses/gpl-2.0.html) + +------------------------------------------------------------------------ diff --git a/screencast b/screencast new file mode 100755 index 0000000..c5854e0 --- /dev/null +++ b/screencast @@ -0,0 +1,1499 @@ +#!/bin/sh + +# screencast - POSIX-compliant shell script to record a X11 desktop +# +# Copyright (c) 2015-2017 Daniel Bermond < yahoo.com: danielbermond > +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 2. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License version 2 for more details. +# +# You should have received a copy of the GNU General Public License version +# 2 along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# An online version of the GNU General Public License version 2 (GPL2) +# can be found at: . + +# program settings +screencast_version="v1.0.0" +screencast_website="https://github.com/bermond/screencast" + +# system related settings +savedir="$(pwd)" # path to save output files +tmpdir="/tmp" # path for temporary files +queue_size="2048" # ffmpeg thread queue size +finish_sound="/usr/share/sounds/freedesktop/stereo/complete.oga" + +# control settings (controls various aspects) +auto_filename="false" # auto choose output filename based on date/time +fade="none" # fade effect +watermark="false" # watermark effect (true, false) +fixed_length="0" # fixed length video in seconds (0 disable) +volume_factor="1.0" # volume increase effect factor (0.0/1.0 disable) +notifications="true" # desktop notifications +audio_encoder="aac" # audio encoder +video_encoder="x264" # video encoder +audio_encoder_setted="false" # controls if audio encoder was setted by cmd line +video_encoder_setted="false" # controls if video encoder was setted by cmd line +format="mp4" # container format (file extension) for output + +# audio settings +audio_input="pulse" +audio_channel_layout="-channel_layout stereo" +audio_general_options="-f alsa -thread_queue_size ${queue_size} \ + -ar 48000 -ac 2 ${audio_channel_layout}" +audio_record_codec="-acodec pcm_s16le -ar 48000 -ac 2" +audio_encode_codec_fdkaac="-acodec libfdk_aac -ab 128k -ar 44100 -ac 2" +audio_encode_codec_aac="-acodec aac -ab 128k -ar 44100 -ac 2" +audio_encode_codec_vorbis="-acodec libvorbis -qscale:a 4 -ar 44100 -ac 2" +audio_encode_codec_opus="-acodec libopus -ab 128k -ar 48000 -ac 2" +audio_encode_codec_mp3lame="-acodec libmp3lame -ab 128k -ar 44100 -ac 2" +audio_encode_codec_shine="-acodec libshine -b 128k -ar 44100 -ac 2" + +#video settings +video_rate="25" # video framerate (fps) +rec_extension="mkv" # container format (file extension) for recording +video_position="0,0" #200,234 # X and Y screen coordinates to record video from +video_size="640x480" # video size (resolution) +video_general_options="-f x11grab -thread_queue_size ${queue_size} \ + -probesize 10M -show_region 1 -region_border 2" +video_record_codec="ffv1" +video_record_codec_vp8="${video_record_codec} -pix_fmt yuv420p" +video_encode_codec_x264="libx264 -r ${video_rate} -crf 21 \ + -preset veryslow -pix_fmt yuv420p" +video_encode_codec_h264_nvenc="h264_nvenc -qmin 10 -qmax 42 \ + -preset slow -cq 10 -bf 2 -g 150 \ + -pix_fmt yuv420p" +video_encode_codec_x265="libx265 -r ${video_rate} -crf 25 \ + -preset veryslow -pix_fmt yuv420p" +video_encode_codec_kvazaar="libkvazaar -r ${video_rate} -kvazaar-params \ + preset=veryslow -pix_fmt yuv420p" +video_encode_codec_hevc_nvenc="hevc_nvenc -r ${video_rate} \ + -preset slow -pix_fmt yuv420p" +video_encode_codec_theora="libtheora -r ${video_rate} -qscale:v 5 \ + -pix_fmt yuv420p" +video_encode_codec_vp8="libvpx -r ${video_rate} -crf 8 -vb 2M \ + -pix_fmt yuv420p" +video_encode_codec_vp9="libvpx-vp9 -r ${video_rate} -crf 30 \ + -vb 0 -pix_fmt yuv420p -speed 0" + +# watermark settings +watermark_size="255x35" +watermark_position="0,0" +watermark_font="Arial" +watermark_text="www.bmftrader.com" + # good position values for hd720p (1280x720) with default watermark size: + # 500,650 - centralized + # 970,10 - top right corner + # 970,650 - bottom right corner + # 10,650 - bottom left corner + +# png (watermark) optimization settings +pngoptimizer="none" # truepng, pingo, optipng, opt-png, none +useadvdef="false" # true, false +truepngsettings="-o max" +pingosettings="-s4" +optipngsettings="-o 7" +advdefsettings="-z4i10" + +# video fade settings +vfade_color="black" # color to be used by the video fade effect +vfade_length="0.6" # length (in seconds) of video fade effect itself +vfade_solid_length="0.1" # solid color length (in seconds) of video fade effect + +# supported arguments (for use with '--list' ('-l')) +supported_fade="in, out, both, none" +supported_formats="mp4, mkv, webm, ogg" +supported_aencoders="aac, opus, vorbis, mp3/mp3lame, shine, \ + none" +supported_vencoders="x264, h264_nvenc, x265, kvazaar, \ + hevc_nvenc, theora, vp8, vp9" +supported_pngopt="truepng, pingo, optipng, opt-png, none" + +######################################### +# functions # +######################################### + +# cleanup function: delete temporary files +# arguments: none +cleanup() { + rm --force "${tmpdir}/screencast-tmpimage-${$}-${randomstring_png}.png" + rm --force "${tmpdir}/screencast-tmpvideo-${tmpvideo_volatile}" +} + +# show_header function: show program header +# arguments: none +show_header() { + printf "%s" "screencast ${screencast_version} - " + printf "%s\n" "Command line interface to record a X11 desktop" + printf "%s" "Copyright (c) 2015-$(date +%Y) " + printf "%s\n" "Daniel Bermond" + printf "%s\n" "$screencast_website" +} + +# help function +# arguments: none +show_help() { + show_header + printf "%s\n" "" + printf "%s\n" "Usage: screencast [options] " + printf "%s\n" " [options] -u" + printf "%s\n" "" + printf "%s" " -o, --output-dir=DIR " + printf "%s\n" "save videos to DIR (to use with -u)" + printf "%s" " -t, --tmp-dir=DIR " + printf "%s\n" "use DIR for temporary files [${tmpdir}]" + printf "%s" " -u, --auto-filename " + printf "%s\n" "auto choose output filename based on date/time" + printf "%s" " -p, --position=N,N " + printf "%s" "recording position (screen XY top left offsets) " + printf "%s\n" "[${video_position}]" + printf "%s" " -s, --size=NxN " + printf "%s\n" "video size (resolution) [${video_size}]" + printf "%s" " -r, --fps=N " + printf "%s\n" "video framerate (fps) [${video_rate}]" + printf "%s" " -f, --format=TYPE " + printf "%s\n" "container format (to use with -u) [${format}]" + printf "%s" " -i, --audio-input=NAME " + printf "%s\n" "audio input device [${audio_input#* }]" + printf "%s" " -a, --audio-encoder=NAME " + printf "%s\n" "audio encoder [${audio_encoder}]" + printf "%s" " -v, --video-encoder=NAME " + printf "%s\n" "video encoder [${video_encoder}]" + printf "%s" " -e, --fade=TYPE " + printf "%s\n" "video fade effect [${fade}]" + printf "%s" " -m, --volume-factor=N " + printf "%s" "volume increase effect factor (1.0 disable) " + printf "%s\n" "[${volume_factor}]" + printf "%s" " -w, --watermark=TEXT " + printf "%s\n" "enable and set text watermark [disabled]" + printf "%s" " -k, --wmark-position=N,N " + printf "%s" "watermark position (video XY top left offsets) " + printf "%s\n" "[${watermark_position}]" + printf "%s" " -z, --wmark-size=NxN " + printf "%s\n" "watermark image size [${watermark_size}]" + printf "%s" " -c, --wmark-font=NAME " + printf "%s\n" "watermark font [${watermark_font}]" + printf "%s" " -x, --fixed=N " + printf "%s" "fixed video length for N seconds (0 disable) " + printf "%s\n" "[${fixed_length}]" + printf "%s" " -n, --no-notifications " + printf "%s\n" "disable desktop notifications" + printf "%s" " -g, --png-optimizer=NAME " + printf "%s\n" "use png (watermark) optimizer and advdef [${pngoptimizer}]" + printf "%s" " -l, --list " + printf "%s\n" "list arguments supported by these options" + printf "%s" " -h, --help " + printf "%s\n" "this help screen" + printf "%s\n" "" + printf "%s\n" "For further help run 'man screencast'" +} + +# notify function: show a desktop notification if setted to do so +# arguments: $1 - urgency level (low, normal, critial) +# $2 - duration in milliseconds +# $3 - icon name +# $4 - text message +notify() { + if [ "$notifications" = "true" ] + then + notify-send \ + --urgency="$1" \ + --expire-time="$2" \ + --icon="$3" \ + "screencast" "$4" + fi +} + +# check_requirements function: check if required programs are installed +# arguments: none +check_requirements() { + # note: although bc is defined by POSIX, some GNU/Linux distributions + # does not include it by default (e.g.: Arch Linux) + for requirement in notify-send ffmpeg ffprobe bc convert magick \ + "$pngoptimizer" advdef + do + # skip disabled components (unnecessary checks) + if { + { + [ "$requirement" = "ffprobe" ] || + [ "$requirement" = "bc" ] ; + } && + [ "$fade" = "none" ] ; + } || + { + { + [ "$requirement" = "convert" ] || + [ "$requirement" = "magick" ] ; + } && + [ "$watermark" = "false" ] ; + } || + { + [ "$requirement" = "$pngoptimizer" ] && + [ "$pngoptimizer" = "none" ] ; + } || + { + [ "$requirement" = "advdef" ] && + [ "$useadvdef" = "false" ] ; + } || + { + [ "$requirement" = "notify-send" ] && + [ "$notifications" = "false" ] ; + } + then + continue + fi + + case "$requirement" in + notify-send) + request_string=" " + installname="${requirement} (libnotify) (or use '-n')" + ;; + ffmpeg) + request_string=" " + installname="ffmpeg (version git master preferred)" + ;; + ffprobe) + request_string=" video fade effect was requested but " + installname="ffprobe (ffmpeg) (version git master preferred)" + ;; + bc) + request_string=" video fade effect was requested but " + installname="$requirement" + ;; + convert|magick) + request_string=" text watermark was requested but " + installname="ImageMagick (IM7 preferred)" + ;; + "$pngoptimizer") + request_string=" png optimization was requested but " + installname="${requirement}" + ;; + advdef) + request_string=" png optimization was requested but " + installname="${requirement} (advancecomp)" + ;; + *) + request_string=" " + installname="$requirement" + ;; + esac + + which "$requirement" >/dev/null 2>&1 || + { + if [ "$requirement" = "magick" ] + then + # in this case IM6 was found because 'convert' goes first + magick() { + convert "$@" + } + continue + else + message="error:${request_string}'${requirement}' was not found" + printf "%s\n" "$message" >&2 + printf "%s\n" " please install ${installname}" >&2 + if [ "$requirement" != "notify-send" ] + then + notify "critical" "5000" "process-stop" "$message" + fi + exit 1 + fi ; + } + done +} + +# command_error function: print an error message regarding invalid command +# line arguments, show notification and exit with error +# arguments: $1 - command line option name (e.g.: "--fade (-e)") +command_error() { + message="error: ${1} option requires an argument" + printf "%s\n%s%s\n" \ + "$message" \ + " if you need help run 'screencast --help' " \ + "or 'man screencast'" >&2 + notify "critical" "5000" "process-stop" "$message" + exit 1 +} + +# exit_program: print an error message to stderr, a desktop notification +# (if it is enabled) and exit with error +# arguments: $1 - error message to print/notificate +exit_program() { + printf "%s\n%s%s\n" \ + "error: ${1}" \ + " if you need help run 'screencast --help' " \ + "or 'man screencast'" >&2 + notify "critical" "5000" "process-stop" "error: $1" + exit 1 +} + +# remove_spaces function: a sed command pipe to remove two or more spaces +# arguments: none +remove_spaces() { + sed 's/[[:space:]][[:space:]]\+/ /' +} + +# list_supported function: print a list of arguments supported by this program +# arguments: none +list_supported() { + show_header + printf "%s\n" "" + printf "%s\n" " Supported arguments:" + printf "%s\n" "" + printf "%s" " -f, --format " + printf "%s\n" "$(printf "%s" "$supported_formats")" + printf "%s" " -a, --audio-encoder " + printf "%s\n" "$(printf "%s" "$supported_aencoders" | remove_spaces)" + printf "%s" " -v, --video-encoder " + printf "%s\n" "$(printf "%s" "$supported_vencoders" | remove_spaces)" + printf "%s" " -e, --fade " + printf "%s\n" "$(printf "%s" "$supported_fade")" + printf "%s" " -g, --png-optimizer " + printf "%s\n" "$(printf "%s" "$supported_pngopt")" + printf "%s\n" "" + printf "%s" " NOTE: selecting vorbis audio encoder does not use " + printf "%s\n" "the low quality FFmpeg " + printf "%s" " built-in vorbis encoder but the high quality " + printf "%s\n" "libvorbis one." + printf "%s\n" "" + printf "%s" " NOTE: mkv is the only container format that supports " + printf "%s\n" "all audio and video " + printf "%s" " encoders. Restrictions apply to other container " + printf "%s\n" "formats." +} + +# parse_cmd_line function: parse command line arguments and adjust variables +# arguments: $1 - the positional parameters passed with double quotes ("$@") +parse_cmd_line() { + shift_count="0" # counts how many 'shift' commands were executed + + while :; do + # since this is a very long case statement only the first block will + # be commented. almost all other blocks follows the same sequence/logic + # and comments will be inserted only for what is different. + case $1 in + # short option and long option without '=' + -i|--audio-input) + # search for an argument + if [ "$2" ] + then + # errors out if no argument was entered after the option + # (will check for a leading '-' in the next parameter, + # meaning that another option was found) + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--audio-input (-i)" + else + audio_input="${2}" # assign value to corresponding var + shift && shift_count="$((shift_count + 1))" + fi + # errors out if no argument is found + else + command_error "--audio-input (-i)" + fi + ;; + # long option with '=' + --audio-input=?*) + audio_input="${1#*=}" # assign value after '=' + ;; + # errors out if a long option with '=' has nothing folling the '=' + --audio-input=) + command_error "--audio-input (-i)" + ;; + + -o|--output-dir) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--output-dir (-o)" + else + savedir="${2%/}" # remove ending '/' if present + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--output-dir (-o)" + fi + ;; + --output-dir=?*) + savedir="${1#*=}" + savedir="${savedir%/}" # remove ending '/' if present + ;; + --output-dir=) + command_error "--output-dir (-o)" + ;; + + -t|--tmp-dir) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--tmp-dir (-t)" + else + tmpdir="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--tmp-dir (-t)" + fi + ;; + --tmp-dir=?*) + tmpdir="${1#*=}" + ;; + --tmp-dir=) + command_error "--tmp-dir (-t)" + ;; + + -p|--position) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--position (-p)" + else + video_position="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--position (-p)" + fi + ;; + --position=?*) + video_position="${1#*=}" + ;; + --position=) + command_error "--position (-p)" + ;; + + -s|--size) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--size (-s)" + else + video_size="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--size (-s)" + fi + ;; + --size=?*) + video_size="${1#*=}" + ;; + --size=) + command_error "--size (-s)" + ;; + + -r|--fps) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--fps (-r)" + else + video_rate="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--fps (-r)" + fi + ;; + --fps=?*) + video_rate="${1#*=}" + ;; + --fps=) + command_error "--fps (-r)" + ;; + + -u|--auto-filename) # option without argument + auto_filename="true" + ;; + + -f|--format) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--format (-f)" + else + format="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--format (-f)" + fi + ;; + --format=?*) + format="${1#*=}" + ;; + --format=) + command_error "--format (-f)" + ;; + + -a|--audio-encoder) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--audio-encoder (-a)" + else + audio_encoder="$2" + audio_encoder_setted="true" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--audio-encoder (-a)" + fi + ;; + --audio-encoder=?*) + audio_encoder="${1#*=}" + audio_encoder_setted="true" + ;; + --audio-encoder=) + command_error "--audio-encoder (-a)" + ;; + + -v|--video-encoder) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--video-encoder (-v)" + else + video_encoder="$2" + video_encoder_setted="true" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--video-encoder (-v)" + fi + ;; + --video-encoder=?*) + video_encoder="${1#*=}" + video_encoder_setted="true" + ;; + --video-encoder=) + command_error "--video-encoder (-v)" + ;; + + -e|--fade) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--fade (-e)" + else + fade="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--fade (-e)" + fi + ;; + --fade=?*) + fade="${1#*=}" + ;; + --fade=) + command_error "--fade (-e)" + ;; + + -m|--volume-factor) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--volume-factor (-u)" + else + volume_factor="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--volume-factor (-m)" + fi + ;; + --volume-factor=?*) + volume_factor="${1#*=}" + ;; + --volume-factor=) + command_error "--volume-factor (-m)" + ;; + + -w|--watermark) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--watermark (-w)" + else + watermark="true" + watermark_text="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--watermark (-w)" + fi + ;; + --watermark=?*) + watermark="true" + watermark_text="${1#*=}" + ;; + --watermark=) + command_error "--watermark (-w)" + ;; + + -z|--wmark-size) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--wmark-size (-z)" + else + watermark_size="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--wmark-size (-z)" + fi + ;; + --wmark-size=?*) + watermark_size="${1#*=}" + ;; + --wmark-size=) + command_error "--wmark-size (-z)" + ;; + + -k|--wmark-position) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--wmark-position (-k)" + else + watermark_position="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--wmark-position (-k)" + fi + ;; + --wmark-position=?*) + watermark_position="${1#*=}" + ;; + --wmark-position=) + command_error "--wmark-position (-k)" + ;; + + -c|--wmark-font) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--wmark-font (-c)" + else + watermark_font="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--wmark-font (-c)" + fi + ;; + --wmark-font=?*) + watermark_font="${1#*=}" + ;; + --wmark-font=) + command_error "--wmark-font (-c)" + ;; + + -x|--fixed) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--fixed (-x)" + else + fixed_length="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--fixed (-x)" + fi + ;; + --fixed=?*) + fixed_length="${1#*=}" + ;; + --fixed=) + command_error "--fixed (-x)" + ;; + + -n|--no-notifications) # option without argument + notifications="false" + ;; + + -g|--png-optimizer) + if [ "$2" ] + then + if { printf "%.1s\n" "$2" | grep -q '-' ; } + then + command_error "--png-optimizer (-g)" + else + pngoptimizer="$2" + shift && shift_count="$((shift_count + 1))" + fi + else + command_error "--png-optimizer (-g)" + fi + ;; + --png-optimizer=?*) + pngoptimizer="${1#*=}" + ;; + --png-optimizer=) + command_error "--png-optimizer (-g)" + ;; + + -l|--list) # option without argument + list_supported + exit 0 + ;; + + -h|-\?|--help) # option without argument + show_help + exit 0 + ;; + + --) # check for the end of options marker '--' + shift && shift_count="$((shift_count + 1))" + break + ;; + + -?*=?*) # unknown option with '=', handle argument also with '=' + printf "%s\n" "error: unknown option \"${1%%=*}\"" >&2 + exit 1 + ;; + + -?*=) # unknown option with '=' + printf "%s\n" "error: unknown option \"${1%=*}\"" >&2 + exit 1 + ;; + + -?*) + printf "%s\n" "error: unknown option \"${1}\"" >&2 + exit 1 + ;; + + *) # no more options left + break + esac + shift && shift_count="$((shift_count + 1))" +done +} + +# check_ffmpeg_format function: check if detected ffmpeg build has support +# for a given format +# arguments: $1 - format generic name +# arguments: $2 - format specific name +# reutrn code: 0 - detected ffmpeg build has support for desired format +# 1 - detected ffmpeg build has no support for desired format +check_ffmpeg_format() { + if ! { ffmpeg -formats -v quiet | grep -q ".*${1}[[:space:]]*${2}.*" ; } + then + printf "%s" "error: " >&2 + printf "%s" "the detected ffmpeg build in $(which ffmpeg) " >&2 + printf "%s\n" "has no support for ${2}" >&2 + printf "%s" " please install a ffmpeg build with " >&2 + printf "%s\n" "support for ${2}" >&2 + notify "critical" "5000" "process-stop" \ + "error: ${2} is not supported by your ffmpeg build" + return 1 + fi +} + +# check_ffmpeg_encoder function: check if detected ffmpeg build has support +# for a given encoder +# arguments: $1 - encoder generic name +# arguments: $2 - encoder specific name +# reutrn code: 0 - detected ffmpeg build has support for desired encoder +# 1 - detected ffmpeg build has no support for desired encoder +check_ffmpeg_encoder() { + if ! { ffmpeg -codecs -v quiet | grep -q ".*${1}.*encoders:.*${2}.*" ; } + then + if [ "$2" != "libfdk_aac" ] + then + printf "%s" "error: " >&2 + printf "%s" "the detected ffmpeg build in $(which ffmpeg) " >&2 + printf "%s\n" "has no support for ${2}" >&2 + printf "%s" " please install a ffmpeg build with " >&2 + printf "%s\n" "support for ${2}" >&2 + notify "critical" "5000" "process-stop" \ + "error: ${2} is not supported by your ffmpeg build" + fi + return 1 + fi +} + +# randomstr function: generate a random string +# arguments: $1 - desired string length +randomstr() { + if [ -c "/dev/urandom" ] + then + rnd="$(LC_CTYPE=C tr -dc '[:alnum:]' < /dev/urandom | head -c"$1")" + elif [ -x "$(which shuf 2>/dev/null)" ] + then + alphanum="a b c d e f g h i j k l m n o p q r s t u v w x y z \ + A B C D E F G H Y J K L M N O P Q R S T U V W X Y Z \ + 0 1 2 3 4 5 6 7 8 9" + # redirect stderr to /dev/null to avoid a warning in some bash versions + { rnd="$(printf "%s" "$(shuf -ez -n"$1" "$alphanum")")"; } 2>/dev/null + elif [ -x "$(which pwgen 2>/dev/null)" ] + then + rnd="$(pwgen -cns "$1" 1)" + elif [ -x "$(which openssl 2>/dev/null)" ] + then + rnd="$(openssl rand -hex "$1" | cut -c-"$1")" + else + rnd="$(awk 'BEGIN{srand(); printf "%d\n",(rand() * 10^8)}')" + while [ "$(printf "%s" "$rnd" | wc -m)" -lt "$1" ] + do + sleep 1 + rnd="$rnd""$(awk 'BEGIN{srand(); printf "%d\n",(rand() * 10^8)}')" + done + rnd="$(printf "%s" "$rnd" | cut -c-"$1")" + fi + + printf "%s" "$rnd" +} + +# optimizepng function: optimize a PNG image with predefined settings +# arguments : $1 - png image file +# return code: 0 - predefined command was executed +# 1 - not a PNG image, predefined command not executed +# note: it will not check if optimization command worked correctly +# note: original image will be modified (make a backup if needed) +optimizepng() { + # check if file is a PNG image + if file "$1" | grep -q 'PNG image data' + then + case "$pngoptimizer" in + truepng) + truepng "$truepngsettings" "$1" + ;; + pingo) + pingo "$pingosettings" "$1" + ;; + optipng) + optipng "$optipngsettings" "$1" + ;; + opt-png) + opt-png "$1" + ;; + none) + : + ;; + esac + + # use advdef if setted to be used (-w / --watermark) + if [ "$useadvdef" = "true" ] + then + advdef "$advdefsettings" "$1" + fi + + else + printf "%s\n" "error: invalid image format (must be PNG)" >&2 + return 1 + fi +} + +# create_watermark function: create a watermark and set watermark options +# to be passed to ffmpeg command +# arguments: none +create_watermark() { + wmark_image="${tmpdir}/screencast-tmpimage-${$}-${randomstring_png}.png" + + # get font pointsize + watermark_pointsize="$(magick \ + -size "$watermark_size" \ + -font "$watermark_font" \ + label:"$watermark_text" \ + -format '%[label:pointsize]' \ + info: 2>/dev/null)" + + # generate the watermark + magick \ + -size "$watermark_size" \ + -font "$watermark_font" \ + -pointsize "$watermark_pointsize" \ + -gravity center \ + \( \ + xc:grey30 \ + -draw "fill gray70 text 0,0 '${watermark_text}'" \ + \) \ + \( \ + xc:black \ + -draw "fill white text 1,1 '${watermark_text}' \ + text 0,0 '${watermark_text}' \ + fill black text -1,-1 '${watermark_text}'" \ + -alpha Off \ + \) \ + -alpha Off \ + -compose copy-opacity \ + -composite \ + -trim \ + +repage \ + "$wmark_image" + + # optimize PNG image file + optimizepng "$wmark_image" + + watermark_options="-r ${video_rate} \ + -thread_queue_size ${queue_size} \ + -i ${wmark_image} \ + -filter_complex overlay=${watermark_position}" +} + +# video_fade function: sets video fade options to be passed to ffmpeg command +# arguments: none +videofade() { + # get recorded video length in seconds + tmp_1stpart="screencast-tmpvideo-${$}-" # split large line + tmp_2ndpart="${randomstring_rec}.${rec_extension}" + videolength="$(ffprobe \ + -i "${tmpdir}/${tmp_1stpart}${tmp_2ndpart}" \ + -show_entries format=duration \ + -v quiet \ + -of csv="p=0")" + + # set start time of fade-out in seconds + total_vfadeout="$(printf "%s\n" "${vfade_length} + \ + ${vfade_solid_length}" | bc)" + vfadeoutstart="$(printf "%s\n" "${videolength} - ${total_vfadeout}" | bc)" + + # build ffmpeg fade in/out options + fadein="fade=type=in:start_time=${vfade_solid_length}" # split large line + fadein="${fadein}:duration=${vfade_length}" + fadein="${fadein}:color=${vfade_color}" + fadeout="fade=type=out:start_time=${vfadeoutstart}" # split large line + fadeout="${fadeout}:duration=${vfade_length}" + fadeout="${fadeout}:color=${vfade_color}" + + # check the choosed fade type and set ffmpeg fade options if necessary + case "$fade" in + in) + fade_options="-vf $fadein" + ;; + out) + fade_options="-vf $fadeout" + ;; + both) + fade_options="-vf ${fadein},${fadeout}" + ;; + esac +} + +######################################### +# program start # +######################################### + +trap 'cleanup' EXIT HUP INT QUIT ABRT TERM # signal handling + +# enable some options if the executing shell is zsh +if [ -n "$ZSH_VERSION" ] +then + which setopt >/dev/null 2>&1 || + { + exit_program \ + "script appears to running in zsh but setopt was not found"; + } + setopt SH_WORD_SPLIT # enable variable word splitting +fi + +parse_cmd_line "$@" # parse command line arguments +shift "$shift_count" # destroy all arguments except a possible output filename + +# check for a valid png optimizer (-g/--png-optimizer) +case "$pngoptimizer" in + truepng|pingo|optipng|opt-png) + useadvdef="true" + ;; + none) + : + ;; + *) + exit_program \ + "'$pngoptimizer' is not a valid PNG optimizer for this program" + ;; +esac + +check_requirements # check if binary requirements are installed + +# check if the detected ffmpeg build has support for basic recording formats +check_ffmpeg_format "x11grab" "X11" || exit 1 +if [ "$audio_input" != "none" ] && + [ "$audio_encoder" != "none" ] +then + check_ffmpeg_format "alsa" "ALSA audio" || exit 1 + if [ "$audio_input" = "pulse" ] + then + check_ffmpeg_format "pulse" "Pulse audio" || exit 1 + fi +fi + +# adjust audio input variable with user input +case "$audio_input" in + none) # video without audio + #disable all audio options (audio will not be recorded) + audio_input="" + audio_channel_layout="" + audio_general_options="" + audio_record_codec="" + audio_encoder="none" + ;; + *) + audio_input="-i ${audio_input}" + ;; +esac + +# if '-u' is not set, make some needed checks and settings +if [ "$auto_filename" = "false" ] +then + # check if user have not entered an output filename after the options + if [ "$#" -eq "0" ] + then + exit_program \ + "you must enter an output filename with extension (or use '-u')" + fi + + # if user specified a save directory directly with output filename that + # is different than the current working directory, use it + # ('-o' setting will be discarded if it was also specified in command line) + if [ "$(dirname "$1")" != "." ] + then + savedir="$(dirname "$1")" + fi + + # if user specified './' as a save directory directly with output + # filename, use it ('pwd' makes the program output more clear) + # ('-o' setting will be discarded if it was also specified in command line) + if { printf "%s" "$1" | grep -q '^\./.*' ; } + then + savedir="$(pwd)" + fi + + # the case that user specifies '../' as a save directory directly with output + # filename is already covered above in 'if [ "$(dirname "$1")" != "." ]'. + # here we just use 'dirname "$(pwd)"' to make the program output more clear + # ('-o' setting will be discarded if it was also specified in command line) + if { printf "%s" "$1" | grep -q '^\.\./.*' ; } + then + savedir="$(printf "%s" "$(dirname "$(pwd)")")" + fi + + # get output filename extension and assign to container format + tmpstr="$(basename "$1")" + tmpstr="${tmpstr##*/}" + output_extension="${tmpstr##*.}" + format="$output_extension" +# if '-u' is set, don't allow to set an output filename in command line +else + if [ "$#" -gt "0" ] + then + exit_program \ + "--auto-filename ('-u') does not allow to set an output filename" + fi +fi + +# check if user entered tilde ('~') as a starting character of $savedir +# ('~' will not expand to $HOME in ffmpeg command line) +case "$savedir" in + "~") + savedir="$HOME" + ;; + "~"*) + savedir="${HOME}${savedir#~}" + ;; + *) + : + ;; +esac + +# check if user entered tilde ('~') as a starting character of $tmpdir +# ('~' will not expand to $HOME in ffmpeg command line) +case "$tmpdir" in + "~") + tmpdir="$HOME" + ;; + "~"*) + tmpdir="${HOME}${tmpdir#~}" + ;; + *) + : + ;; +esac + +# check for valid output and tmp directories (-o/--output-dir and -t/--tmp-dir) +for directory in "$savedir" "$tmpdir" +do + # check if the entered $savedir/$tmpdir already exists and mkdir dir if not + if ! [ -e "$directory" ] + then + mkdir -p "$savedir" 2>/dev/null || + { + exit_program "failed to create save direcotry '${savedir}'"; + } + fi + + # check if the entered $savedir/$tmpdir is a directory + if [ -d "$directory" ] + then + # check if the entered $savedir/$tmpdir has write permission + if ! [ -w "$directory" ] + then + exit_program "no write permission for directory '${directory}'" + fi + else + exit_program "'${directory}' is not a directory" + fi +done + +# check for a valid screen position format to record (N,N) (-p/--position) +if ! { printf "%s" "$video_position" | grep -Eq '^[0-9]+,[0-9]*$' ; } +then + exit_program "'${video_position}' is not a valid screen position format" +fi + +# check for a valid video size format (NxN) (-s/--size) +if ! { printf "%s" "$video_size" | grep -Eq '^[0-9]+x[0-9]*$' ; } +then + exit_program "'${video_size}' is not a valid video size format" +fi + +# check if entered framerate (fps) is a valid integer/float number (-r/--fps) +if ! { printf "%s" "$video_rate" | grep -Eq '^[0-9]+\.?[0-9]*$' ; } +then + exit_program "'${video_rate}' is not a valid video framerate (fps) format" +fi + +# check if a valid container format was selected (-f/--format) and change +# audio/video encoder for some needed formats if not setted by command line +case "$format" in + mp4) + faststart="-movflags +faststart" + ;; + mkv) + : # no action needed for 'mkv' format + ;; + webm) + if [ "$auto_filename" = "false" ] + then + if [ "$audio_encoder_setted" = "false" ] + then + audio_encoder="opus" + fi + if [ "$video_encoder_setted" = "false" ] + then + video_encoder="vp9" + fi + fi + ;; + ogg) + if [ "$auto_filename" = "false" ] + then + if [ "$audio_encoder_setted" = "false" ] + then + audio_encoder="vorbis" + fi + if [ "$video_encoder_setted" = "false" ] + then + video_encoder="theora" + fi + fi + ;; + *) + message="'${format}' is not a valid container \ + format for this program" + exit_program "$(printf "%s" "$message" | remove_spaces)" + ;; +esac + +# check for invalid combination of audio encoder and container format +if { + [ "$format" = "mp4" ] && + { + [ "$audio_encoder" = "opus" ] ; + } ; + } || + { + [ "$format" = "webm" ] && + { + { [ "$audio_encoder" = "aac" ] ; } || + { [ "$audio_encoder" = "mp3" ] ; } || + { [ "$audio_encoder" = "mp3lame" ] ; } || + { [ "$audio_encoder" = "shine" ] ; } ; + } ; + } || + { + [ "$format" = "ogg" ] && + { + { [ "$audio_encoder" = "aac" ] ; } || + { [ "$audio_encoder" = "mp3" ] ; } || + { [ "$audio_encoder" = "mp3lame" ] ; } || + { [ "$audio_encoder" = "shine" ] ; } ; + } ; + } +then + exit_program \ + "container format ${format} does not support ${audio_encoder} encoder" +fi + +# check for invalid combination of video encoder and container format +if [ "$format" = "mp4" ] && [ "$video_encoder" = "vp9" ] +then + # special case for mp4 + vp9 (support is experimental and not enabled) + message="support for vp9 encoder in mp4 container format is \ + currently experimental and not enabled" + exit_program "$(printf "%s" "$message" | remove_spaces)" +fi +if { + [ "$format" = "mp4" ] && + { + { [ "$video_encoder" = "theora" ] ; } || + { [ "$video_encoder" = "vp8" ] ; } ; + } ; + } || + { + [ "$format" = "webm" ] && + { + { [ "$video_encoder" = "x264" ] ; } || + { [ "$video_encoder" = "x265" ] ; } || + { [ "$video_encoder" = "kvazaar" ] ; } || + { [ "$video_encoder" = "theora" ] ; } ; + } ; + } || + { + [ "$format" = "ogg" ] && + { + { [ "$video_encoder" = "x264" ] ; } || + { [ "$video_encoder" = "x265" ] ; } || + { [ "$video_encoder" = "kvazaar" ] ; } || + { [ "$video_encoder" = "vp9" ] ; } ; + } ; + } +then + exit_program \ + "container format ${format} does not support ${video_encoder} encoder" +fi + +# set recording and encoding options for the selected audio encoder +case "$audio_encoder" in + aac) + if check_ffmpeg_encoder aac libfdk_aac + then + audio_encode_codec="$audio_encode_codec_fdkaac" + else + audio_encode_codec="$audio_encode_codec_aac" + fi + ;; + vorbis) + check_ffmpeg_encoder vorbis libvorbis || exit 1 + audio_encode_codec="$audio_encode_codec_vorbis" + ;; + opus) + check_ffmpeg_encoder opus libopus || exit 1 + audio_encode_codec="$audio_encode_codec_opus" + ;; + mp3|mp3lame) + check_ffmpeg_encoder mp3 libmp3lame || exit 1 + audio_encode_codec="$audio_encode_codec_mp3lame" + ;; + shine) + check_ffmpeg_encoder mp3 libshine || exit 1 + audio_encode_codec="$audio_encode_codec_shine" + ;; + none) # video without audio + #disable all audio options (audio will not be recorded) + audio_input="" + audio_channel_layout="" + audio_general_options="" + audio_record_codec="" + ;; + *) + exit_program "'${audio_encoder}' is not a valid audio encoder" + ;; +esac + +# set recording and encoding options for the selected video encoder +case "$video_encoder" in + x264) + check_ffmpeg_encoder h264 libx264 || exit 1 + video_encode_codec="$video_encode_codec_x264" + ;; + h264_nvenc) + check_ffmpeg_encoder h264 h264_nvenc || exit 1 + video_encode_codec="$video_encode_codec_h264_nvenc" + ;; + x265) + check_ffmpeg_encoder hevc libx265 || exit 1 + video_encode_codec="$video_encode_codec_x265" + ;; + kvazaar) + check_ffmpeg_encoder hevc libkvazaar || exit 1 + video_encode_codec="$video_encode_codec_kvazaar" + ;; + hevc_nvenc) + check_ffmpeg_encoder hevc hevc_nvenc || exit 1 + video_encode_codec="$video_encode_codec_hevc_nvenc" + ;; + theora) + check_ffmpeg_encoder theora libtheora || exit 1 + video_encode_codec="$video_encode_codec_theora" + ;; + vp8) + check_ffmpeg_encoder vp8 libvpx || exit 1 + video_record_codec="$video_record_codec_vp8" + video_encode_codec="$video_encode_codec_vp8" + ;; + vp9) + check_ffmpeg_encoder vp9 libvpx-vp9 || exit 1 + video_encode_codec="$video_encode_codec_vp9" + ;; + *) + exit_program "'${video_encoder}' is not a valid video encoder" + ;; +esac + +# check if a valid fade effect was entered (-e/--fade) +case "$fade" in + in|out|both|none) + : + ;; + *) + exit_program "'${fade}' is not a valid fade effect" + ;; +esac + +# check if entered fixed video length is a valid integer/float number (-x) +if { printf "%s" "$fixed_length" | grep -Eq '^[0-9]+\.?[0-9]*$' ; } +then + # check if user enabled fixed video duration (disabled by default) + if ! { printf "%s" "$fixed_length" | grep -Eq '^[0]+\.?[0]*$' ; } + then + fixed_length_options="-t ${fixed_length}" + fi +else + exit_program \ + "'${fixed_length}' is not a valid number for fixed video length" +fi + +# check if entered volume factor is a valid integer/float number (-m) +if { printf "%s" "$volume_factor" | grep -Eq '^[0-9]+\.?[0-9]*$' ; } +then + # check if volume increase effect is disabled (value '1.0' or '0.0') + if { printf "%s" "$volume_factor" | grep -Eq '^[0]+\.?[0]*$' ; } || + { printf "%s" "$volume_factor" | grep -Eq '^[1]+\.?[0]*$' ; } + then + volume_options="" + else + volume_options="-af volume=${volume_factor}" + fi +else + exit_program \ + "'${volume_factor}' is not a valid number for volume increase effect" +fi + +# check for a valid watermark size format (NxN) (-z/--wmark-size) +if ! { printf "%s" "$watermark_size" | grep -Eq '^[0-9]+x[0-9]*$' ; } +then + exit_program "'${watermark_size}' is not a valid watermark size format" +fi + +# check for a valid watermark position format (N,N) (-k/--wmark-position) +if ! { printf "%s" "$watermark_position" | grep -Eq '^[0-9]+,[0-9]*$' ; } +then + exit_program \ + "'${watermark_position}' is not a valid watermark position format" +else + # translate watermark position to what is really used in ffmpeg command + watermark_position="$(printf "%s" "$watermark_position" | tr ',' ':')" +fi + +# enable watermark effect if necessary (-w/--watermark) +if [ "$watermark" = "true" ] +then + randomstring_png="$(randomstr "20")" # random string for tmp png filename + create_watermark +fi + +randomstring_rec="$(randomstr "20")" # random string for tmp video filename +tmpvideo_volatile="${$}-${randomstring_rec}.${rec_extension}" + +notify "normal" "1700" "media-record" "recording..." + +# record screen to a lossless video +# shellcheck disable=SC2086 +if ffmpeg \ + $audio_general_options $audio_input \ + $video_general_options -r $video_rate -s $video_size \ + -i :0.0+$video_position \ + $watermark_options \ + $audio_record_codec \ + -vcodec $video_record_codec -r $video_rate \ + $fixed_length_options \ + -y \ + "${tmpdir}/screencast-tmpvideo-${tmpvideo_volatile}" +then + notify "normal" "3000" "media-playback-stop" "encoding..." + + # set fade effect if necessary (-e/--fade) + case "$fade" in + in|out|both) + videofade + ;; + *) + : + ;; + esac + + # set output filename + if [ "$auto_filename" = "true" ] + then + output_file="screencast-$(date +%Y-%m-%d_%H.%M.%S).${format}" + else + output_file="$(basename "$1")" + fi + + # encode the recorded lossless video file + # shellcheck disable=SC2086 + if ffmpeg \ + $audio_channel_layout \ + -i "${tmpdir}/screencast-tmpvideo-${tmpvideo_volatile}" \ + $fade_options \ + $volume_options \ + $audio_encode_codec \ + -vcodec $video_encode_codec -r $video_rate \ + $faststart \ + -y \ + "${savedir}/${output_file}" + then + notify "normal" "3000" "mail-mark-notjunk" "finish" + + # play a sound after finish if requirements are present + if [ -x "$(which paplay 2>/dev/null)" ] && [ -f "$finish_sound" ] + then + paplay "$finish_sound" 2>/dev/null + fi + else + printf "%s\n" "screencast: encoding error!" >&2 + notify "critical" "5000" "process-stop" "encoding error!" + exit 1 + fi +else + printf "%s\n" "screencast: recording error!" >&2 + notify "critical" "5000" "process-stop" "recording error!" + exit 1 +fi diff --git a/screencast.1 b/screencast.1 new file mode 100644 index 0000000..85e18a4 --- /dev/null +++ b/screencast.1 @@ -0,0 +1,366 @@ +." screencast manpage +.TH screencast "1" "February 2017" "version 1.0.0" "User Commands" +.SH NAME +\fBscreencast\fR - command line interface to record a X11 desktop +.SH SYNOPSIS +.nf +\fBscreencast\fR [\fIoptions\fR] output +\fBscreencast\fR [\fIoptions\fR] \fB\-u\fR +.fi +.PP +The specified output filename must have an extension which in turn must be a +supported container format. +.SH DESCRIPTION +\fBscreencast\fR is a command line interface to record a X11 desktop using +FFmpeg. It's designed to make desktop recording a simple task, eliminating the +somewhat complex FFmpeg command line arguments and the need of multiple +commands. It uses predefined encoder settings that should be suitable for most +needs. The default settings provides a quick and affordable way to record the +desktop, letting the user to be focused on just specifying the desired video +position and size. If the user doesn't want to stick with the default settings +it is possible to choose among a set of supported encoders and container +formats. +.PP +\fBscreencast\fR not only provides an easy way to record your desktop, but it +also has options to automatically add some effects to the recordings, like +video fade-in / fade-out, text watermarking and volume increase. +.SH OPTIONS +Long options can be used with spaces or an equal sign ('='). For example, +\fB\-\-fade \fIin\fR is the same as \fB\-\-fade\fR=\fIin\fR. +.TP +\fB\-o\fR, \fB\-\-output\-dir\fR=\fIDIR\fR +.RS +Set the output video to be saved in \fIDIR\fR. This is to be used with +\fB\-u\fR option (if you want to specify a save directory when using automatic +output filename choosing). When not using \fB\-u\fR option you can specify the +output directory directly in the output filename. +.PP +default: the local directory +.RE +.TP +\fB\-t\fR, \fB\-\-tmp\-dir\fR=\fIDIR\fR +.RS +Set temporary files to be placed in \fIDIR\fR. By default, the \fI/tmp\fR +directory will be used for temporary files, which usually is a ramdisk +filesystem in most systems. You may want to change it if you have limited RAM +and/or are recording very long videos. Make sure to have enough free space in +the specified directory. +.PP +default: /tmp +.RE +.TP +\fB\-u\fR, \fB\-\-auto\-filename\fR +.RS +Auto choose output filename based on date and time. The output filename will +have the following format: +.PP +.nf +screencast-YEAR-MONTH-DAY_HOUR.MINUTE.SECOND.FORMAT +.fi +.RE +.TP +\fB\-p\fR, \fB\-\-position\fR=\fIN\fR,\fIN\fR +.RS +The screen position defining from where the recording will take place. These +are X and Y offsets from the screen top left corner. Combined with \fB\-s\fR +option it will define a rectangular desktop area that will be recorded. +.PP +default: 0,0 (screen top left corner) +.RE +.TP +\fB\-s\fR, \fB\-\-size\fR=\fIN\fRx\fIN\fR +.RS +The video size. This is actually the video resolution. Combined with \fB\-p\fR +option it will define a rectangular desktop area that will be recorded. +.PP +default: 640x480 +.RE +.TP +\fB\-r\fR, \fB\-\-fps\fR=\fIN\fR +.RS +Video framerate (frames per second - fps). +.PP +default: 25 +.RE +.TP +\fB\-f\fR, \fB\-\-format\fR=\fITYPE\fR +.RS +Container format of the output video. This is to be used with \fB\-u\fR option +(if you want to specify a container format when using automatic output filename +choosing). When not using \fB\-u\fR option you can specify the container format +directly in the output filename. +.PP +.nf + default: mp4 +supported types: mp4, mkv, webm, ogg +.fi +.RE +.TP +\fB\-i\fR, \fB\-\-audio\-input\fR=\fINAME\fR +.RS +ALSA audio input device. When setted to \fInone\fR the audio will be disabled +(video without audio, only video stream will be present). To determine possible +audio input device names please see: +.nf + +.fi +.PP +default: pulse +.RE +.TP +\fB\-a\fR, \fB\-\-audio\-encoder\fR=\fINAME\fR +.RS +Audio encoder to be used to encode the recorded audio. When setted to +\fInone\fR the audio will be disabled (video without audio, only video stream +will be present). +.PP +.nf + default: aac +supported types: aac, opus, vorbis, mp3/mp3lame, shine, none +.fi +.RE +.TP +\fB\-v\fR, \fB\-\-video\-encoder\fR=\fINAME\fR +.RS +Video encoder to be used to encode the recorded video. If using a NVIDIA +hardware accelerated encoder please make sure that you have a NVIDIA graphics +card that supports the choosed encoder. +.PP +.nf + default: x264 +supported types: x264, h264_nvenc, x265, kvazaar, hevc_nvenc, theora, vp8, vp9 +.fi +.RE +.TP +\fB\-e\fR, \fB\-\-fade\fR=\fITYPE\fR +.RS +Video fade effect to be added to the recorded video. When setted to \fInone\fR +the recorded video will have no fade effect. +.PP +.nf + default: none +supported types: in, out, both, none +.fi +.RE +.TP +\fB\-m\fR, \fB\-\-volume\-factor\fR=\fIN\fR +.RS +Volume increase effect factor. This will increase the volume of the recorded +audio. Normally, audio volume is low with default settings, even if you +increse your microphone capture volume. Use this to give your videos a better +hearing experience, letting your viewers fell more confortable to watch it +whithout needing to rise their sound volume. It works as a percentage factor. +For example, a value of \fI1.5\fR will increase volume by 50% and a value of +\fI2.0\fR will double volume. When setted to \fI1.0\fR or \fI0.0\fR this effect +is disabled. +.PP +default: 1.0 +.RE +.TP +\fB\-w\fR, \fB\-\-watermark\fR=\fITEXT\fR +.RS +Enable text watermarking, setting text to \fITEXT\fR. Although it is a text, +it is generated as a PNG image so it can be integrated in the video. +.PP +default: disabled +.RE +.TP +\fB\-k\fR, \fB\-\-wmark\-position\fR=\fIN\fR,\fIN\fR +.RS +Set text watermark position inside the video. These are X and Y offsets from +the video top left corner (not from the screen). Combined with \fB\-z\fR option +it will define a rectangular area in the video that will contain the text +watermark image. +.PP +default: 970,10 +.RE +.TP +\fB\-z\fR, \fB\-\-wmark\-size\fR=\fIN\fRx\fIN\fR +.RS +Set text watermark size. Combined with \fB\-k\fR option it will define a +rectangular area in the video that will contain the text watermark image. +.PP +default: 255x35 +.RE +.TP +\fB\-c\fR, \fB\-\-wmark\-font\fR=\fINAME\fR +.RS +Set text watermark font to \fINAME\fR. +.PP +.nf +default: Arial + NOTE: if the default or setted font is not installed it will be auto choosed +.fi +.RE +.TP +\fB\-x\fR, \fB\-\-fixed\fR=\fIN\fR +.RS +Set the video to have a fixed length of \fIN\fR seconds. When setted to \fI0\fR +this is disabled, meaning a indefinite video length that will be recorded until +the user stops it by presing the \fIq\fR key in the terminal window. +.PP +default: 0 +.RE +.TP +\fB\-n\fR, \fB\-\-no\-notifications\fR +Disable desktop notifications. Desktop notifications are shown by default, +allowing a better visual control of the recording. Use this option to disable +them. +.TP +\fB\-g\fR, \fB\-\-png\-optimizer\fR=\fINAME\fR +.RS +Use PNG optimizer \fINAME\fR and \fIadvdef\fR (advancecomp) in the PNG image +generated by \fB\-w\fR option that will be used as a text watermark. This +option is useful when you want to use a big text watermark in a big video, +allowing the video to be a few bytes smaller. Not really needed if using +default watermark settings with a small text. When setted to \fInone\fR PNG +optimization is disabled. +.PP +.nf + default: none +supported ones: truepng, pingo, optipng, opt-png, none +.fi +.RE +.TP +\fB\-l\fR, \fB\-\-list\fR +List arguments supported by these options. +.TP +\fB\-h\fR, \fB\-\-help\fR +Help screen. +.SH EXAMPLES +Use all default settings: +.RS +.PP +\fBscreencast\fR myvideo.mp4 +.RE +.PP +Use default settings for a 1280x720 video from screen positon 200,234 with +auto choosen output filename: +.RS +.PP +\fBscreencast\fR \fB\-p\fR 200,234 \fB\-s\fR 1280x720 \fB\-u\fR +.RE +.PP +Changing just the container format without specifying encoders will make it to +auto choose them. In this case, the 'webm' format will produce a video with +opus and vp9 encoders: +.RS +.PP +\fBscreencast\fR /home/user/webmvideos/myvideo.webm +.RE +.PP +Specifying save dir and container format, with auto choosen encoders and +output filename. In this case, the 'ogg' format will produce a video with +vorbis (libvorbis) and theora encoders: +.PP +.RS +\fBscreencast\fR \fB\-o\fR /home/user/myvideos \fB\-f\fR ogg \fB\-u\fR +.RE +.PP +1280x720 video from screen positon 200,234 , 30 fps, mp3 (libmp3lame) audio +encoder, x265 video encoder, mkv container format, fade-in video effect, volume +increase effect of 50%, small text watermark in top right video corner: +.RS +.PP +\fBscreencast\fR \fB\-p\fR 200,234 \fB\-s\fR 1280x720 \fB\-r\fR 30 \fB\-a\fR +mp3 \fB\-v\fR x265 \fB\-e\fR in \fB\-m\fR 1.5 \fB\-w\fR www.mysitehere.com +myvideo.mkv +.RE +.PP +\fINOTE\fR: +.PP +When not using the \fB\-x\fR option press the \fIq\fR key in terminal window to +end the recording. +.SH REQUIREMENTS +The minimum requirement is a recent \fIFFmpeg\fR version compiled with support +for x11grab and the desired encoders. For example, if you want to use \fIvp9\fR +video encoder and \fIopus\fR audio encoder it will require \fIFFmpeg\fR to be +compiled with support for x11grab, libvpx and libopus. It's advised to use +\fIFFmpeg\fR version git master. +.PP +When recording audio (\fB\-i\fR and \fB\-a\fR options not setted to +\fInone\fR) \fIFFmpeg\fR must have been compiled with support for ALSA audio. +The default \fIpulse\fR setting for \fB\-i\fR option requires \fIFFmpeg\fR to +be compiled with support for pulseaudio (libpulse) as well. +.PP +\fInotify\-send\fR (libnotify) is needed for desktop notifications. Note that +desktop notifications are enabled by default. They can be disabled by using +the \fB\-n\fR option, eliminating the need of \fInotify\-send\fR. Running +\fBscreencast\fR in a system without \fInotify\-send\fR and without using the +\fB\-n\fR option will result in error. +.PP +Other requirements are needed according to additional options that may be +specified by the user: +.RS +.PP +\fIFFprobe\fR and \fIbc\fR are needed for video fade effect (\fB\-e\fR option). +.PP +\fIImageMagick\fR is needed for text watermarking (\fB\-w\fR option). Both IM6 +and IM7 are supported, but IM7 is preferred. +.PP +At least one supported PNG optimizer and \fIadvdef\fR (advancecomp) are needed +for PNG (watermark) optimization (\fB\-g\fR option). +.RE +.SH REMARKS +\fBscreencast\fR uses a two step recording process. Firstly the audio and +video are recorded to a lossless format and at a second stage it is encoded +to produce the output video. That's why you see a desktop notification +saying 'encoding...'. This two step mechanism allows a better video and avoids +problems. +.PP +When using \fIaac\fR audio encoder (which is the default setting), +\fBscreencast\fR will check if the detected FFmpeg build has support for +libfdk_aac and use it if present, otherwise it will use the FFmpeg built\-in +AAC audio encoder. Make sure to have a recent FFmpeg version as older versions +do not support the built\-in AAC audio encoder without being experimental, or +do not support it at all. +.PP +FFmpeg encoder names have the 'lib' prefix removed for simplicity. For example, +libx264 is called \fIx264\fR in this program. +.PP +Although the \fIvorbis\fR audio encoder is mentioned in the options, it is made +this way just for simplicity as mentioned right above. When the user selects +the \fIvorbis\fR audio encoder \fBscreencast\fR uses the libvorbis FFmpeg +encoder, which has a much superior quality than the FFmpeg built\-in vorbis +encoder. +.PP +The \fImkv\fR container format is the only one that supports all audio and +video encoders. All other container formats have restrictions. \fBscreencast\fR +will exit with error if an unsupported encoder is choosed for a given container +format. For example, you cannot use the \fIopus\fR audio encoder with \fImp4\fR +container format. +.PP +When using the \fImp4\fR container format, the moov atom will be automatically +moved to the beginning of the output video file. This is the same as running +\fIqt-faststart\fR in the output video and is useful for uploading it to +streaming websites like \fIYouTube\fR. +.PP +The default settings for container format and audio/video encoders will produce +a video that is ready to be uploaded to \fIYouTube\fR. +.PP +The default \fIpulse\fR audio input setting (\fB\-i\fR option) will be suitable +for most users as it will use the default recording device configured in +pulseaudio, as long as FFmpeg was compiled with ALSA and pulseaudio support. +.PP +\fIOxygen\fR icon names are used for displaying desktop notifications. Although +not a requirement, \fIOxygen\fR icons are recommended to be installed for a +better visual integration. +.PP +\fBscreencast\fR will try to play a notification sound when the encoding +process is finished. For this, it will use \fIpaplay\fR (from \fIpulseaudio\fR) +and a sound file from the freedesktop sound theme (usually a package called +\fIsound-theme-freedesktop\fR in most Linux distributions). Although not a +requirement, they are recommended to be installed for a better user experience. +.SH BUGS +None are known at the moment. +.SH AUTHOR +Daniel Bermond < yahoo\-com: danielbermond > +.PP + +.SH COPYRIGHT +Copyright \(co 2015-2017 Daniel Bermond +.SH LICENSE +GNU General Public License version 2 (GPL2) + +.SH SEE ALSO +ffmpeg(1)