Updated 2014-06-30 23:57:03 by uniquename

uniquename - 2014may30

Near the bottom of my 'bio' page at uniquename, I have a list of 'done and to-do' utilities in a section labelled 'CFE' (Code - Front Ends).

In the 'to do' list, there was an item titled

  • Tk GUI Front End for 'ffmpeg' - for video-and-audio capture of a computer monitor session

That is the subject of this page.

---

THE GOALS

My goals for the Tcl-Tk script for this GUI were:

*** Provide entry widgets for the approximately 15 parameters that can be specified to 'ffmpeg' in creating a movie file. Provide working defaults for the parameters.

*** Provide an entry widget for an output filename, with a default name provided.

*** Provide an entry widget to allow the user to specify an movie-player program with which to view a completed movie file.

*** Provide a 'Launch' button to start the movie capture.

*** Provide an entry widget to allow the user to specify a 'delay time' before 'ffmpeg' is started up --- so that the user has time to do some preparation, such as minimizing this GUI window, before 'ffmpeg' recording is started.

*** Provide a 'Play' button to initiate playing of the completed movie file.

*** To avoid overwhelming the user with the number of recording parameters available, provide a checkbutton on the GUI to only show the video/audio/other parameters if the user requests to see them.

---

THE GUI LAYOUT

Like for some image/media/animated-GIF 'find-and-play' utilities that I have posted here, I made a 'text-sketch' for the GUI for this 'movie-capture' utility.

CONVENTIONS for the GUI 'text-sketch' below:

  • SQUARE-BRACKETS indicate a comment not to be included on the GUI.
  • BRACES indicate a Tk 'button' widget.
  • UNDERSCORES indicate a Tk 'entry' widget.
  • A COLON indicates that the text before the colon is on a 'label' widget.
  • CAPITAL-O indicates a Tk 'radiobutton' widget.
  • CAPITAL-X indicates a Tk 'checkbutton' widget.
   Frame
   names      --------------------------------------------------------------------------------------
     |        Movie-and-Audio Movie-Capture - a front-end for the 'ffmpeg' command
     V        [window title]
              --------------------------------------------------------------------------------------
 .fRbuttons   {Exit} {Help} {LaunchMovieCapture} {PlayMovie}  X ShowDetailedInputParms (video,audio,other) Delay time (secs): 8__

 .fRmsg       'Delay time' allows some setup time before the 'ffmpeg'-window pops up and ffmpeg starts
              capturing the screen. For example: It allows time to minimize this GUI.
              [This initial message in a label widget may be changed when the 'Launch' button is clicked.]

              --------------------------------------------------------------------------------------
 .fRouthead   Output File parameters:
              --------------------------------------------------------------------------------------

 .fRcontainer Container format: O Matroska (.mkv) O Mpeg4 (.mp4) O Mpeg (.mpg) O Flash (.flv) O AVI (.avi) O WEBM (.webm)

 .fRfile      Output movie filename : /tmp/${USER}_screen_capture_movie.mkv______________  {Browse...}

 .fRplayer    Player for the movie file: totem________ Examples: totem  gmplayer  mplayer  ffplay  vlc

 [The following frames are shown if the 'ShowDetailedInputParms' checkbuttons is set ON.]

              --------------------------------------------------------------------------------------
 .fRvideohead Video parameters:
              --------------------------------------------------------------------------------------

 .fRvidsize   Video size: 1024x768____ Examples: 640x480 , 800x600 , 1024x768

 .fRvidoffset Offset on screen: +0,0_____  Examples: +0,0   +10,30   +100,50  Video-in format: x11grab__

 .fRvsource   Source (display ID): :0.0___ Examples: :0.0  :0.1               Video rate (frames/sec): 25_

 .fRvcodec    Video codec: libx264_____ Examples: libx264  mpeg4  mpeg1video  flv  ...

 .fRvother    Other video parms: -vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset_______

              -------------------------------------------------------------------------------------
 .fRaudiohead Audio parameters:
              -------------------------------------------------------------------------------------

 .fRaformat    Audio format: alsa____   Examples: alsa  oss        Audio Channels: 1_ Examples: 1  2

 .fRainterface Audio interface: pulse____   Examples: pulse  hw:0,0  /dev/dsp

 .fRacodec     Audio codec: pcm_s16le__ Examples: pcm_s16le  libmp3lame  libfaac  vorbis

 .fRaother     Other audio parms: -ar 22050 -ab 96k_________________________________________________

              --------------------------------------------------------------------------------------
 .fRgeneral   General parameters:
              --------------------------------------------------------------------------------------

 .fRthreads   Threads: 1___ (to take advantage of a multi-core computer)

 .fRguide     NOTE: This utility runs 'ffmpeg' in an 'xterm' window. Startup and coding messages from 'ffmpeg'
              can be seen in that window. Minimize the window to get it out of the way of recording. Stop the
              recording by re-opening the 'xterm' window and typing 'q'. The terminal does not close after
              'ffmpeg' stops, so that you can examine msgs. THEN CLOSE the terminal window. The output file,
              if good, can be shown in a movie player, that you specify above.  See 'Help' for details.
              [a 'label' widget]
             ---------------------------------------------------------------------------------------

---

GUI Components

From the GUI 'sketch' above, it is seen that the GUI consists of about
   4 'button' widgets
  25 'label'  widgets (many are for entry fields)
  14 'entry'  widgets
   1 'checkbutton' widget
   6 'radiobutton' widgets
   0 'scale'  widgets
   0 'canvas' widgets
   0 'listbox' widgets
   0 'text' widgets

All but the 'label' widgets provide operating parameters/options in this utility. Hence there are about 4+14+1+6 = 25 options on this utility.

---

I should point out here that I was not especially interested in coming up with a 'beautiful utility'. I just wanted a utility that would make starting a recording session with 'ffmpeg' as simple as a click on a 'Launch' button.

I am certainly interested in making pretty GUI's --- as I have expressed on my 'bio' page at uniquename, and as my pages at Experiments in making embellished GUI's and Version 2 of a demo of THEMES for Tk GUI's, using images and colors have indicated.

But at this time, I am satisfied to implement the 'functionality', and let the 'beauty' go for a later date (when I have more beauty tools/code at hand).

SCREENSHOTS OF THE GUI

On the basis of the GUI-layout sketch above, I ended up with the GUI seen in the following image.

The operation can be as simple as clicking on the 'LaunchMovieCapture' button --- and then clicking on the 'PlayMovie' button, after the movie file has been created --- if you take the initial defaults.

Note that there are several radiobuttons that allow you to choose the 'container format' of the output file. But you can simply take the default.

(And you can change the default by changing a 'set CONTAINERformat' statement at the bottom of the Tk script.)

---

If the user wants to change (or simply check) the video and audio and 'other' parameters that are set according to a choice of the 'container format', the user can click on the 'ShowDetailedInputParms' checkbutton at the top of the GUI.

When that checkbutton is clicked, the GUI expands downward, as can be seen in the following image.

---

THE CONTAINER FORMATS

I have tested the 5 active container-format radiobuttons to confirm that the video-audio-other parameters that I have provided for each container-format do indeed result in a successful movie file capture.

So I have created '.mkv' '.mp4' '.mpg' '.flv' and '.avi' files.

I have grayed out the WEBM radiobutton. That is intended to eventually allow for creating a movie in the 'webm' format that Google is promoting. It uses a Matroska-like container format and a Vorbis audio format and a 'VP8' video format. You can see some information on the WEBM format at [1].

I do not have the video codec that is needed to make that file format --- and my 2009 version of 'ffmpeg' may not be capable of creating a WEBM file. But I include most of the program code to easily implement and activate that option.

DESCRIPTION OF THE CODE

Below, I provide the Tk script code for this 'movie-capture-from-computer-screen' utility.

I follow my usual 'canonical' structure for Tk code for this Tk script:
  0) Set general window & widget parms (win-name, win-position,
     win-color-scheme, fonts-for-widgets, widget-geometry-parms,
     text-array-for-labels-etc, win-size-control).

  1a) Define ALL frames (and sub-frames, if any).
  1b) Pack   ALL frames and sub-frames.

  2) Define & pack all widgets in the frames, frame by frame.
              Within each frame, define ALL the widgets.
              Then pack the widgets.

  3) Define keyboard and mouse/touchpad/touch-sensitive-screen action
     BINDINGS, if needed.

  4) Define PROCS, if needed.

  5) Additional GUI initialization (typically with one or more of
     the procs), if needed.

This Tk coding structure is discussed in more detail on the page A Canonical Structure for Tk Code --- and variations.

This structure makes it easy for me to find code sections --- while generating and testing a Tk script, and when looking for code snippets to include in other scripts (code re-use).

I call your attention to step-zero. One thing that I started doing in 2013 is use of a text-array for text in labels, buttons, and other widgets in the GUI. This can make it easier for people to internationalize my scripts. I will be using a text-array like this in most of my scripts in the future.

Experimenting with the GUI

As in all my scripts that use the 'pack' geometry manager (which is all of my 100-plus scripts, so far), I provide the four main pack parameters --- '-side', '-anchor', '-fill', '-expand' --- on all of the 'pack' commands for the frames and widgets.

That helps me when I am initially testing the behavior of a GUI (the various widgets within it) as I resize the main window.

I think that I have used a pretty nice choice of the 'pack' parameters. The label and button and radiobutton widgets stay fixed in size and relative-location if the window is re-sized --- while the output-filename and 'player-program' entry widgets expand/contract horizontally whenever the window is re-sized horizontally.

You can experiment with the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various frames and widgets --- to get the widget behavior that you want.

___

Additional experimentation: You might want to change the fonts used for the various GUI widgets. For example, you could change '-weight' from 'bold' to 'normal' --- or '-slant' from 'roman' to 'italic'. Or change font families.

In fact, you may NEED to change the font families, because the families I used may not be available on your computer --- and the default font that the 'wish' interpreter chooses may not be very pleasing.

I use variables to set geometry parameters of widgets --- parameters such as border-widths and padding. And I have included the '-relief' parameter on the definitions of frames and widgets. Feel free to experiment with those 'appearance' parameters as well.

If you find the gray palette of the GUI is not to your liking, you can change the value of the RGB parameter supplied to the 'tk_setPalette' command near the top of the code.

Some features in the code

There are plenty of comments in the code, to describe what most of the code-sections are doing.

You can look at the top of the PROCS section of the code to see a list of the procs used in this script, along with brief descriptions of how they are called and what they do.

The main procs are
  'set_defaults_for_container' - called by bindings on the CONTAINER
                                 radiobuttons.

                                 Sets defaults for the GUI widgets for a given
                                 container type.

  'capture_movie'              - called by the 'LaunchMovieCapture' button.

                                 Launches the 'ffmpeg' program --- with user-selected
                                 recording parameters. Calls an external shell script
                                 whose code is provided below.

  'play_movie'                 - called by the 'PlayMovie' button.

                                 Launches a user-selected movie 'player' program.

  'pack_detail_frames'         - called by button1-release binding on the
                                 ShowDetailedInputParms checkbutton.

  'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.

I used the following statement to allow the GUI to be expanded in the x-direction, but NOT the y-direction.
   wm resizable . 1 0

It is my hope that the copious comments in the code will help Tcl-Tk coding 'newbies' get started in making GUI's like this.

Without the comments, potential young Tcler's might be tempted to return to their iPhones and iPads and iPods --- to watch old George Carlin videos --- and videos of his comedy offspring, Louis C.K.

 Code for Tk script 'monitorAndAudio_MovieCapture_ffmpeg_FrontEnd.tk' :

#!/usr/bin/wish -f
##
## Tk SCRIPT NAME: monitorAndAudio_MovieCapture_ffmpeg_FrontEnd.tk
##
##+#######################################################################
## PURPOSE:  This Tk script provides a GUI for using the 'ffmpeg' program
##           to make a MOVIE file by capturing
##           1) VIDEO from a computer monitor
##           AND
##           2) AUDIO from the computer's audio board/circuitry.
##
##           The GUI is intended to make the user aware of the options
##           available without the user needing to use the
##           'man ffmpeg' or 'ffmpeg -h' commands or other 'ffmpeg'
##           documentation --- for example, web searches.
##
##           Also the GUI is meant to provide defaults for all the
##           movie-making parameters that are known to work (provided
##           the necessary video and audio codec libraries are available.)
##
##           The options available to the user are indicated
##           by the following 'sketch' of the GUI:
##
## ---------------------------------------------------------------------
##
## NOTE ON SKETCH CONVENTION for GUI sketch below:
##
## Square-brackets indicate a comment not to be included on the GUI.
## Braces indicate a Tk 'button' widget.
## Underscores indicate a Tk 'entry' widget.
## A colon indicates that the text before the colon is on a 'label' widget.
## Capital-O indicates a Tk 'radiobutton' widget.
## Capital-X indicates a Tk 'checkbutton' widget.
##
##
##   Frame
##   names      --------------------------------------------------------------------------------------
##     |        Movie-and-Audio Movie-Capture - a front-end for the 'ffmpeg' command
##     V        [window title]
##              --------------------------------------------------------------------------------------
## .fRbuttons   {Exit} {Help} {LaunchMovieCapture} {PlayMovie}  X ShowDetailedInputParms (video,audio,other) Delay time (secs): 8__ 
##
## .fRmsg       'Delay time' allows some setup time before the 'ffmpeg'-window pops up and ffmpeg starts
##              capturing the screen. For example: It allows time to minimize this GUI.
##              [This initial message in a label widget may be changed when the 'Launch' button is clicked.]
##
##              --------------------------------------------------------------------------------------
## .fRouthead   Output File parameters:
##              --------------------------------------------------------------------------------------
##
## .fRcontainer Container format: O Matroska (.mkv) O Mpeg4 (.mp4) O Mpeg (.mpg) O Flash (.flv) O AVI (.avi) O WEBM (.webm)
##
## .fRfile      Output movie filename : /tmp/${USER}_screen_capture_movie.mkv______________  {Browse...}
##
## .fRplayer    Player for the movie file: totem________ Examples: totem  gmplayer  mplayer  ffplay  vlc
##
## [The following frames are shown if the 'ShowDetailedInputParms' checkbuttons is set ON.]
##
##              --------------------------------------------------------------------------------------
## .fRvideohead Video parameters:
##              --------------------------------------------------------------------------------------
##
## .fRvidsize   Video size: 1024x768____ Examples: 640x480 , 800x600 , 1024x768
##
## .fRvidoffset Offset on screen: +0,0_____  Examples: +0,0   +10,30   +100,50  Video-in format: x11grab__
##
## .fRvsource   Source (display ID): :0.0___ Examples: :0.0  :0.1               Video rate (frames/sec): 25_
##
## .fRvcodec    Video codec: libx264_____ Examples: libx264  mpeg4  mpeg1video  flv  ...
##
## .fRvother    Other video parms: -vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset_______
##
##              -------------------------------------------------------------------------------------
## .fRaudiohead Audio parameters:
##              -------------------------------------------------------------------------------------
##
## .fRaformat    Audio format: alsa____   Examples: alsa  oss        Audio Channels: 1_ Examples: 1  2
##
## .fRainterface Audio interface: pulse____   Examples: pulse  hw:0,0  /dev/dsp     
##
## .fRacodec     Audio codec: pcm_s16le__ Examples: pcm_s16le  libmp3lame  libfaac  vorbis
##
## .fRaother     Other audio parms: -ar 22050 -ab 96k_________________________________________________
##
##              --------------------------------------------------------------------------------------
## .fRgeneral   General parameters:
##              --------------------------------------------------------------------------------------
##
## .fRthreads   Threads: 1___ (to take advantage of a multi-core computer)
##
## .fRguide     NOTE: This utility runs 'ffmpeg' in an 'xterm' window. Startup and coding messages from 'ffmpeg'
##              can be seen in that window. Minimize the window to get it out of the way of recording. Stop the
##              recording by re-opening the 'xterm' window and typing 'q'. The terminal does not close after
##              'ffmpeg' stops, so that you can examine msgs. THEN CLOSE the terminal window. The output file,
##              if good, can be shown in a movie player, that you specify above.  See 'Help' for details. 
##              [a 'label' widget]
##             ---------------------------------------------------------------------------------------
##
##+##############
## GUI components:
##
## From the GUI 'sketch' above, it is seen that the GUI consists of
## ABOUT:
##
##   4 'button' widgets
##  25 'label'  widgets (many are for entry fields)
##  14 'entry'  widgets
##   1 'checkbutton' widget
##   6 'radiobutton' widgets
##   0 'scale'  widgets
##   0 'canvas' widgets
##   0 'listbox' widgets
##   0 'text' widgets
##
##+#####################################################################
## CALLED BY:  This script could be put in a sub-directory of the
##             users home directory, such as
##                   $HOME/apps/tkMonitorAndAudioMovieCapture.
##
##             Then the user can use their desktop system (such as
##             Gnome or KDE) to set up the script as an icon on the
##             desktop. Then the user can click on the icon to
##             startup the script.
##+########################################################################
## STRUCTURE OF THIS CODE:
##
##  0) Set general window parms (win-name, win-position, win-color-scheme,
##     fonts, widget-geom-parms, win-size-control, text-array-for-labels-etc).
##
##  1a) Define ALL frames (and sub-frames, if any).
##  1b) Pack the frames.
##
##  2) Define & pack all widgets in the frames, frame by frame.
##     After all the widgets for a frame are defined, pack them in the frame.
##
##  3) Define keyboard and/or mouse/touchpad/touch-sensitive-screen 'event'
##     BINDINGS, if needed.
##  4) Define PROCS, if needed.
##  5) Additional GUI INITIALIZATION (typically with one or more of
##     the procs), if needed.
##
## In more detail:
##
##  1a) Define ALL frames -- and sub-frames:
##
##   Top-level :
##       'fRbuttons'     for Exit, Help, and Capture buttons
##       'fRmsg'         for a label widget (for messages)
##       'fRouthead'     for a label widget (for a heading)
##       'fRcontainer'   for a label and several radiobutton widgets
##       'fRoutfile'     for label-entry widgets
##       'fRplayer'      for label-entry-label widgets
##       'fRvideohead'   for a label widget (for a heading)
##       'fRvidsize'     for label-entry-label widgets
##       'fRvidoffset'   for label-entry-label widgets
##       'fRvsource'     for label-entry-label widgets
##       'fRvcodec'      for label-entry-label widgets
##       'fRvother'      for label-entry widgets
##       'fRaudiohead'   for a label widget (for a heading)
##       'fRaformat'     for label-entry widgets
##       'fRainterface'  for 2 label-entry widgets
##       'fRacodec'      for label-entry widgets
##       'fRaother'      for label-entry widgets
##       'fRotherhead'   for a label widget (for a heading)
##       'fRthreads'     for label-entry-label widgets
##       'fRguide'       for a label widget (for usage info)
##
##       About 21 frames, each about 1 or 2 characters high.
##
##  1b) Pack ALL frames, including sub-frames.
##
##  2) Define & pack all widgets in the frames -- basically going through
##     frames & their interiors in  left-to-right, top-to-bottom order:
##
##  3) Define bindings:  See BINDINGS section below.
##
##  4) Define procs:
##
##    'launch_ffmpeg'        - called by the 'LaunchCapture' button.
##
##   'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
##
##     For other procs, see the PROCS section below.
##
##  5) Additional GUI initialization:  See this section at the bottom
##                                     of this script.
##+#######################################################################
## DEVELOPED WITH: Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october, 'Karmic Koala')
##
##   $ wish
##   % puts "$tcl_version $tk_version"
##
## showed
##     8.5 8.5
## but this script should work in most previous 8.x versions, and probably
## even in some 7.x versions (if font handling is made 'old-style').
##+########################################################################
## MAINTENANCE HISTORY:
## Started by: Blaise Montandon 2014apr22 Started development, on Ubuntu 9.10,
##                                        with the aim of getting the GUI up
##                                        first --- procs later.
## Updated by: Blaise Montandon 2014apr24 Started implementing the procs.
## Updated by: Blaise Montandon 2014may29 Started testing. Added VIDEOrate
##                                        entry field.
## Updated by: Blaise Montandon 2014may30 Moved Delay-time entry field from its
##                                        own frame to the 'fRbuttons' frame.
##                                        Added the 'fRmsg' frame and label. 
##+#######################################################################

##+######################################################
## Set WINDOW TITLE and POSITION.
##+######################################################

wm title    . "Monitor-and-Audio Movie-Capture - a front end for the 'ffmpeg' command"
wm iconname . "MovieCapture"

wm geometry . +15+30


##+######################################################
## Set the COLOR SCHEME for the window and its widgets ---
## such as listbox and entry field background color.
##+######################################################

tk_setPalette "#e0e0e0"

  set headBKGD  "#a0a0a0"
  set guideBKGD "#00ff00"

  set entryBKGD "#ffffff"
  set textBKGD  "#f0f0f0"
  set radbuttBKGD  "#c0c0c0"
  set chkbuttBKGD  "#c0c0c0"
# set scaleBKGD "#f0f0f0"
# set listboxBKGD "#ffffff"


##+########################################################
## DEFINE (temporary) FONT NAMES.
##
## We use a VARIABLE-WIDTH font for text on LABEL and
## BUTTON widgets.
##
## We use a FIXED-WIDTH font for LISTBOX lists,
## for text in ENTRY fields --- and often for text in
## TEXT widgets.
##+########################################################

font create fontTEMP_varwidth \
   -family {comic sans ms} \
   -size -14 \
   -weight bold \
   -slant roman

font create fontTEMP_SMALL_varwidth \
   -family {comic sans ms} \
   -size -12 \
   -weight bold \
   -slant roman

## Some other possible (similar) variable width fonts:
##  Arial
##  Bitstream Vera Sans
##  DejaVu Sans
##  Droid Sans
##  FreeSans
##  Liberation Sans
##  Nimbus Sans L
##  Trebuchet MS
##  Verdana


font create fontTEMP_fixedwidth  \
   -family {liberation mono} \
   -size -14 \
   -weight bold \
   -slant roman

font create fontTEMP_SMALL_fixedwidth  \
   -family {liberation mono} \
   -size -12 \
   -weight bold \
   -slant roman

## Some other possible fixed width fonts (esp. on Linux):
##  Andale Mono
##  Bitstream Vera Sans Mono
##  Courier 10 Pitch
##  DejaVu Sans Mono
##  Droid Sans Mono
##  FreeMono
##  Nimbus Mono L
##  TlwgMono


##+###########################################################
## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS.
## (e.g. width and height of canvas, and padding for Buttons)
##+###########################################################

## LABEL widget geom settings:

set PADXpx_label 0
set PADYpx_label 0
set BDwidthPx_label 2
set RELIEF_label_lo "flat"


## BUTTON widget geom settings:

set PADXpx_button 0
set PADYpx_button 0
set BDwidthPx_button 2
## We use '-relief raised' for all 'button' widgets.


## ENTRY widget geom settings:

set BDwidthPx_entry 2
## We use '-relief sunken' for all 'entry' widgets.


## RADIOBUTTON widget geom settings:

set PADXpx_radbutton 0
set PADYpx_radbutton 0
set BDwidthPx_radbutt 2
set RELIEF_radbutt_hi "raised"


## CHECKBUTTON widget geom settings:

set PADXpx_chkbutton 0
set PADYpx_chkbutton 0
set BDwidthPx_chkbutt 2
set RELIEF_chkbutt_hi "raised"

## TEXT widget geom settings:

set BDwidthPx_text 2
# set RELIEF_numtext "ridge"

## SCALE widget geom parameters:

# set BDwidthPx_scale 2
# set scaleThicknessPx 10


##+##############################################################
## Set a TEXT-ARRAY to hold text for buttons & labels on the GUI.
##     NOTE: This can aid INTERNATIONALIZATION. This array can
##           be set according to a nation/region parameter.
##+##############################################################

## if { "$VARlocale" == "en"}

## For '.fRbuttons' frame:

set aRtext(buttonEXIT)    "Exit"
set aRtext(buttonHELP)    "Help"
set aRtext(buttonCAPTURE) "LaunchMovieCapture"
set aRtext(buttonPLAY)    "PlayMovie"
set aRtext(chkbuttSHOWdetail) "ShowDetailedInputParms (video,audio,other)"
set aRtext(labelDELAY)    "Delay time (secs):"

## For '.fRmsg' frame:

set aRtext(labelMSG) \
"'Delay time' allows some setup time before the window titled 'ffmpeg' pops up and ffmpeg
starts capturing the screen. For example, the delay allows time to minimize this GUI."


## For '.fRouthead' frame:

set aRtext(labelOUTHEAD) "Output File Parameters:"

## For '.fRcontainer' frame:

set aRtext(labelCONTAINER) "Container format:"

set aRtext(radbuttMATROSKA) "Matroska (.mkv)"
set aRtext(radbuttMPEG4)    "Mpeg4 (.mp4)"
set aRtext(radbuttMPEG)     "Mpeg (.mpg)"
set aRtext(radbuttFLV)      "Flash (.flv)"
set aRtext(radbuttAVI)      "AVI (.avi)"
set aRtext(radbuttWEBM)     "WEBM (.webm)"

## For '.fRoutfile' frame:

set aRtext(labelOUTFILE) "Output  movie  filename :"

## For '.fRplayer' frame:

set aRtext(labelPLAYER1) "Player for the movie file:"
set aRtext(labelPLAYER2) "Examples: totem  gmplayer  mplayer  ffplay  vlc"


## For '.fRvideohead' frame:

set aRtext(labelVIDEOHEAD) "Video recording parameters:"

## For '.fRvsize' frame:

set aRtext(labelVSIZE1) "Video size:"
set aRtext(labelVSIZE2) "Examples: 640x480   800x600   1024x768"

## For '.fRvoffset' frame:

set aRtext(labelVOFFSET1) "Offset on screen:"
set aRtext(labelVOFFSET2) "Examples: +0,0   +10,30   +100,50"

## For '.fRvsource' frame:

set aRtext(labelVSOURCE1) "Source (display ID):"
set aRtext(labelVSOURCE2) "Examples: :0.0   :0.1"

set aRtext(labelVFORMAT1) "Video format:"
set aRtext(labelVFORMAT2) "Examples: x11grab"

## For '.fRvcodec' frame:

set aRtext(labelVCODEC1) "Video codec:"
set aRtext(labelVCODEC2) "Examples: libx264  mpeg4  mpeg2video  flv ...    "

set aRtext(labelVRATE1)  "Video rate (frames/sec):"
set aRtext(labelVRATE2)  "Examples: 25 30 24"

## For '.fRvother' frame:

set aRtext(labelVOTHER) "Other video parms:"


## For '.fRaudiohead' frame:

set aRtext(labelAUDIOHEAD) "Audio recording parameters:"

## For '.fRaformat' frame:

set aRtext(labelAFORMAT1) "Audio format:"
set aRtext(labelAFORMAT2) "Examples: alsa  oss"

## For '.fRainterface' frame:

set aRtext(labelAINTERFACE1) "Audio interface (software):"
set aRtext(labelAINTERFACE2) "Examples: pulse  hw:0,0  /dev/dsp"

set aRtext(labelACHANNELS1) "Audio channels:"
set aRtext(labelACHANNELS2) "Examples: 1  2"

## For '.fRacodec' frame:

set aRtext(labelACODEC1) "Audio codec:"
set aRtext(labelACODEC2) "Examples: pcm_s16le  libmp3lame  libfaac  vorbis"

## For '.fRaother' frame:

set aRtext(labelAOTHER) "Other audio parameters:"


## For '.fRotherhead' frame:

set aRtext(labelOTHERHEAD) "Other recording parameters:"

## For '.fRthreads' frame:

set aRtext(labelTHREADS1) "Threads:"
set aRtext(labelTHREADS2) "(to take advantage of a multi-core computer)"


## For '.fRguide' frame:

set aRtext(labelGUIDE) \
"NOTE: This utility runs 'ffmpeg' in an 'xterm' window. Startup and coding messages from 'ffmpeg'
can be seen in that window. Minimize the window to get it out of the way of recording. Stop the
recording by re-opening the 'xterm' window and typing 'q'. The terminal does not close after
'ffmpeg' stops, so that you can examine msgs. THEN CLOSE the terminal window. The output file,
if good, can be shown with a video player, that you specify above.  See 'Help' for details."


## END OF  if { "$VARlocale" == "en"}


##+######################################################################
## Set a MIN-SIZE of the window (roughly).
##
## For WIDTH, allow for the min-width of the '.fRbuttons' frame.
##
## For HEIGHT, allow for the INITIAL stacked frames:
##      1 char   high for the '.fRbuttons'   frame
##      1 char   high for the '.fRmsg'       frame
##      1 char   high for the '.fRouthead'   frame
##      1 char   high for the '.fRcontainer' frame
##      1 char   high for the '.fRoutfile'   frame
##      1 char   high for the '.fRplayer'    frame
##+#####################################################################

## FOR WIDTH: (allow for widgets in the '.fRbuttons' frame)

set minWidthPx [font measure fontTEMP_varwidth \
   " $aRtext(buttonEXIT) $aRtext(buttonHELP) $aRtext(buttonCAPTURE)  \
$aRtext(buttonPLAY)  $aRtext(chkbuttSHOWdetail)  $aRtext(labelDELAY)"]

## We add some pixels to account for right-left-size of
## window-manager decoration (~8 pixels) and some pixels for
## frame/widget borders (~6 widgets x 4 pixels/widget = 24 pixels).

set minWinWidthPx [expr {32 + $minWidthPx}]

##+#################################################
## For HEIGHT --- for
##      1 char   high for the '.fRbuttons'   frame
##      1 char   high for the '.fRmsg'       frame
##      1 char   high for the '.fRouthead'   frame
##      1 char   high for the '.fRcontainer' frame
##      1 char   high for the '.fRoutfile'   frame
##      1 char   high for the '.fRplayer'    frame
##    --------
##      6 chars  high for the 6 frames
##+#################################################

set charHeightPx [font metrics fontTEMP_varwidth -linespace]

set minWinHeightPx [expr {6 * $charHeightPx}]

## Add about 20 pixels for top-bottom window decoration --
## and some pixels for top-and-bottom of frame/widget borders
## (~6 widgets x 4 pixels/widget = 24 pixels).

set minWinHeightPx [expr {44 + $minWinHeightPx}]


## FOR TESTING:
#   puts "minWinWidthPx = $minWinWidthPx"
#   puts "minWinHeightPx = $minWinHeightPx"

wm minsize . $minWinWidthPx $minWinHeightPx


## We may allow the window to be resizable.  We pack some entry widgets
## (and the frames that contain them --- .fRoutfile, .fRvother, .fRaother)
## with '-fill x -expand 1' so that the entry widgets can be enlarged by
## enlarging the window.

## If you want to make the window un-resizable,
## you can use the following statement.
#   wm resizable . 0 0

## Allow the window to resize in x-direction, but not y.
   wm resizable . 1 0

##+####################################################################
##+####################################################################
## DEFINE *ALL* THE FRAMES:
##
##   Top-level :
##      '.fRbuttons'
##      .... (about 18 frames, 1 char high)
##      '.fRthreads'
##      and
##      5 chars  high for the 'fRguide'    frame
##
##   Sub-frames: None
##+####################################################################
##+####################################################################

set RELIEF_frame flat
set BDwidth_frame 0

## FOR TESTING of expansion of frames (esp. during window expansion):
# set RELIEF_frame raised
# set BDwidth_frame 2

frame .fRbuttons   -relief $RELIEF_frame  -bd $BDwidth_frame

# frame .fRmsg     -relief $RELIEF_frame  -bd $BDwidth_frame
  frame .fRmsg     -relief raised         -bd 2

frame .fRouthead   -relief raised  -borderwidth 2

frame .fRcontainer -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRoutfile   -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRplayer    -relief $RELIEF_frame  -bd $BDwidth_frame


frame .fRvideohead -relief raised         -bd 2

frame .fRvsize     -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRvoffset   -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRvsource   -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRvcodec    -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRvother    -relief $RELIEF_frame  -bd $BDwidth_frame


frame .fRaudiohead   -relief raised         -bd 2

frame .fRaformat     -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRainterface  -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRacodec      -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRaother      -relief $RELIEF_frame  -bd $BDwidth_frame


frame .fRotherhead   -relief raised         -bd 2

frame .fRthreads     -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRguide       -relief raised         -bd 2


##+########################################################
## PACK *ALL* the FRAMES.
##+########################################################

pack .fRbuttons \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

pack .fRmsg \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRouthead \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRcontainer \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

pack .fRoutfile \
   -side top \
   -anchor nw \
   -fill x \
   -expand 1

pack .fRplayer \
   -side top \
   -anchor nw \
   -fill x \
   -expand 1

## We pack the 'video, 'audio' and 'other' frames in
## proc 'pack_detail_frames' which is in the PROCS section
## below. This proc can be used to show-hide the 'detail'
## frames, via a checkbutton on the GUI.


## OK. All frames are defined --- and all are packed (except
## the 'detail' frames). Now for the widgets.


##+################################################################
##+################################################################
## START DEFINING & PACKING WIDGETS WITHIN THEIR FRAMES.
##+################################################################
##+################################################################


##+##########################################################
## IN THE '.fRbuttons' frame -- DEFINE several BUTTON widgets
## --- Exit, Help, LaunchMovieCapture, PlayMovie. Also DEFINE
## a CHECKBUTTON widget. And DEFINE 1 LABEL-ENTRY pair for
## 'Delay time'.
## Then PACK THE WIDGETS.
##+##########################################################

button .fRbuttons.buttEXIT \
   -text "$aRtext(buttonEXIT)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {exit}

button .fRbuttons.buttHELP \
   -text "$aRtext(buttonHELP)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {popup_msgVarWithScroll .topHelp "$HELPtext"}

button .fRbuttons.buttCAPTURE \
   -text "$aRtext(buttonCAPTURE)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {
   .fRmsg.labelMSG configure -text "Control window will appear in $DELAYseconds secs."
   update idletasks
   capture_movie
   .fRmsg.labelMSG configure -text "$aRtext(labelMSG)"}

button .fRbuttons.buttPLAY \
   -text "$aRtext(buttonPLAY)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {play_movie}

## DEFINE Checkbuttons for Show/Hide-DetailFrames.

set SHOWdetail0or1 0

checkbutton  .fRbuttons.chkbuttSHOWdetail \
   -text "$aRtext(chkbuttSHOWdetail)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable SHOWdetail0or1 \
   -selectcolor "$chkbuttBKGD" \
   -relief $RELIEF_chkbutt_hi \
   -bd $BDwidthPx_chkbutt

## DEFINE label-and-entry widgets, for 'Delay time'.

label .fRbuttons.labelDELAY \
   -text "$aRtext(labelDELAY)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRbuttons.entryDELAY \
   -textvariable DELAYseconds \
   -bg $entryBKGD \
   -width 3 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

##+##########################################
## Pack the widgets in the '.fRbuttons' frame.
##+##########################################

pack .fRbuttons.buttEXIT \
     .fRbuttons.buttHELP \
     .fRbuttons.buttCAPTURE \
     .fRbuttons.buttPLAY \
     .fRbuttons.chkbuttSHOWdetail \
     .fRbuttons.labelDELAY \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRbuttons.entryDELAY \
   -side left \
   -anchor w \
   -fill x \
   -expand 0


##+########################################################
## IN THE '.fRmsg' frame -- DEFINE 1 LABEL widget.
## Then PACK IT.
##+########################################################

label .fRmsg.labelMSG \
   -text "$aRtext(labelMSG)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label \
   -bg "#ccffcc"

pack .fRmsg.labelMSG \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+########################################################
## IN THE '.fRouthead' frame -- DEFINE 1 LABEL widget.
## Then PACK IT.
##+########################################################

label .fRouthead.labelOUTHEAD \
   -text "$aRtext(labelOUTHEAD)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief flat \
   -bd $BDwidthPx_label \
   -bg $headBKGD

pack .fRouthead.labelOUTHEAD \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+########################################################
## IN THE '.fRcontainer' frame -- DEFINE 1 LABEL widget,
## and several RADIOBUTTON widgets. Then PACK THEM.
##+########################################################

label .fRcontainer.labelCONTAINER \
   -text "$aRtext(labelCONTAINER)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## DEFINE Radiobuttons for container formats :

radiobutton .fRcontainer.radbuttMATROSKA \
   -text "$aRtext(radbuttMATROSKA)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable CONTAINERformat \
   -value "matroska" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

radiobutton .fRcontainer.radbuttMPEG4 \
   -text "$aRtext(radbuttMPEG4)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable CONTAINERformat \
   -value "mpeg4" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

# .fRcontainer.radbuttMPEG4 configure -state disabled

radiobutton .fRcontainer.radbuttMPEG \
   -text "$aRtext(radbuttMPEG)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable CONTAINERformat \
   -value "mpeg" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

# .fRcontainer.radbuttMPEG configure -state disabled

radiobutton .fRcontainer.radbuttFLV \
   -text "$aRtext(radbuttFLV)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable CONTAINERformat \
   -value "flv" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

# .fRcontainer.radbuttFLV configure -state disabled


radiobutton .fRcontainer.radbuttAVI \
   -text "$aRtext(radbuttAVI)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable CONTAINERformat \
   -value "avi" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

# .fRcontainer.radbuttAVI configure -state disabled

radiobutton .fRcontainer.radbuttWEBM \
   -text "$aRtext(radbuttWEBM)" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable CONTAINERformat \
   -value "webm" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_radbutt

.fRcontainer.radbuttWEBM configure -state disabled

## Pack the widgets in frame '.fRcontainer'.

pack .fRcontainer.labelCONTAINER \
     .fRcontainer.radbuttMATROSKA \
     .fRcontainer.radbuttMPEG4 \
     .fRcontainer.radbuttMPEG \
     .fRcontainer.radbuttFLV \
     .fRcontainer.radbuttAVI \
     .fRcontainer.radbuttWEBM \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+########################################################
## IN THE '.fRoutfile' frame -- DEFINE 1 LABEL widget
## and 1 ENTRY widget. Then PACK THEM.
##+########################################################

label .fRoutfile.labelOUTFILE \
   -text "$aRtext(labelOUTFILE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRoutfile.entryOUTFILE \
   -textvariable ENTRYfilename \
   -bg $entryBKGD \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

## COMMENTED OUT this 'Browse' button, for now.
if {0} {
button .fRoutfile.buttBROWSE \
   -text "$aRtext(buttonBROWSE)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {get_outfilename}
}

## PACK the widgets in the 'fRoutfile' frame.

pack .fRoutfile.labelOUTFILE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRoutfile.entryOUTFILE \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

## COMMENTED OUT this 'Browse' button, for now.
if {0} {
pack .fRoutfile.buttBROWSE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0
}

##+########################################################
## IN THE '.fRplayer' frame -- DEFINE a LABEL-ENTRY-LABEL
## triplet of widgets. Then PACK THEM.
##+########################################################

label .fRplayer.labelPLAYER1 \
   -text "$aRtext(labelPLAYER1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRplayer.entryPLAYER \
   -textvariable ENTRYplayer \
   -bg $entryBKGD \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRplayer.labelPLAYER2 \
   -text "$aRtext(labelPLAYER2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## PACK the widgets in the 'fRplayer' frame.

pack .fRplayer.labelPLAYER1 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRplayer.entryPLAYER \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

pack .fRplayer.labelPLAYER2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+########################################################
## IN THE '.fRvideohead' frame -- DEFINE 1 LABEL widget.
## Then PACK IT.
##+########################################################

label .fRvideohead.labelVIDEOHEAD \
   -text "$aRtext(labelVIDEOHEAD)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label \
   -bg $headBKGD

pack .fRvideohead.labelVIDEOHEAD \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+########################################################
## IN THE '.fRvsize' frame -- DEFINE a LABEL-ENTRY-LABEL
## triplet of widgets. Then PACK THEM.
##+########################################################

label .fRvsize.labelVSIZE1 \
   -text "$aRtext(labelVSIZE1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRvsize.entryVSIZE \
   -textvariable VIDEOsize \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRvsize.labelVSIZE2 \
   -text "$aRtext(labelVSIZE2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## PACK the widgets in the 'fRvsize' frame.

pack  .fRvsize.labelVSIZE1 \
      .fRvsize.entryVSIZE \
      .fRvsize.labelVSIZE2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+########################################################
## IN THE '.fRvoffset' frame -- DEFINE a LABEL-ENTRY-LABEL
## triplet of widgets. Then PACK THEM.
##+########################################################

label .fRvoffset.labelVOFFSET1 \
   -text "$aRtext(labelVOFFSET1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRvoffset.entryVOFFSET \
   -textvariable VIDEOoffset \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRvoffset.labelVOFFSET2 \
   -text "$aRtext(labelVOFFSET2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## PACK the widgets in the 'fRvoffset' frame.

pack  .fRvoffset.labelVOFFSET1 \
      .fRvoffset.entryVOFFSET \
      .fRvoffset.labelVOFFSET2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+###############################################################
## IN THE '.fRvsource' frame -- DEFINE 2 sets of LABEL-ENTRY-LABEL
## triplets of widgets. Then PACK THEM.
##+###############################################################

label .fRvsource.labelVSOURCE1 \
   -text "$aRtext(labelVSOURCE1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRvsource.entryVSOURCE \
   -textvariable VIDEOsource \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRvsource.labelVSOURCE2 \
   -text "$aRtext(labelVSOURCE2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

label .fRvsource.labelVFORMAT1 \
   -text "$aRtext(labelVFORMAT1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRvsource.entryVFORMAT \
   -textvariable VIDEOformat \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRvsource.labelVFORMAT2 \
   -text "$aRtext(labelVFORMAT2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## PACK the widgets in the 'fRvsource' frame.

pack  .fRvsource.labelVSOURCE1 \
      .fRvsource.entryVSOURCE \
      .fRvsource.labelVSOURCE2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack  .fRvsource.labelVFORMAT2 \
      .fRvsource.entryVFORMAT \
      .fRvsource.labelVFORMAT1 \
   -side right \
   -anchor e \
   -fill none \
   -expand 0


##+########################################################
## IN THE '.fRvcodec' frame -- DEFINE a LABEL-ENTRY-LABEL
## triplet of widgets. Then PACK THEM.
##+########################################################

label .fRvcodec.labelVCODEC1 \
   -text "$aRtext(labelVCODEC1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRvcodec.entryVCODEC \
   -textvariable VIDEOcodec \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRvcodec.labelVCODEC2 \
   -text "$aRtext(labelVCODEC2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

label .fRvcodec.labelVRATE1 \
   -text "$aRtext(labelVRATE1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRvcodec.entryVRATE \
   -textvariable VIDEOrate \
   -bg $entryBKGD \
   -width 3 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRvcodec.labelVRATE2 \
   -text "$aRtext(labelVRATE2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## PACK the widgets in the 'fRvcodec' frame.

pack  .fRvcodec.labelVCODEC1 \
      .fRvcodec.entryVCODEC \
      .fRvcodec.labelVCODEC2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack  .fRvcodec.labelVRATE2 \
      .fRvcodec.entryVRATE \
      .fRvcodec.labelVRATE1 \
   -side right \
   -anchor e \
   -fill none \
   -expand 0


##+########################################################
## IN THE '.fRvother' frame -- DEFINE a LABEL-ENTRY
## pair of widgets. Then PACK THEM.
##+########################################################

label .fRvother.labelVOTHER \
   -text "$aRtext(labelVOTHER)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRvother.entryVOTHER \
   -textvariable VIDEOotherParms \
   -bg $entryBKGD \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

#   -width 10 \

## PACK the widgets in the 'fRvother' frame.

pack  .fRvother.labelVOTHER \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack  .fRvother.entryVOTHER \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+########################################################
## IN THE '.fRaudiohead' frame -- DEFINE 1 LABEL widget.
## Then PACK IT.
##+########################################################

label .fRaudiohead.labelAUDIOHEAD \
   -text "$aRtext(labelAUDIOHEAD)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label \
   -bg $headBKGD

## PACK the widgets in the 'fRaudiohead' frame.

pack  .fRaudiohead.labelAUDIOHEAD \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+########################################################
## IN THE 'fRaformat' frame -- DEFINE a LABEL-ENTRY-LABEL
## triplet of widgets. Then PACK THEM.
##+########################################################

label .fRaformat.labelAFORMAT1 \
   -text "$aRtext(labelAFORMAT1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRaformat.entryAFORMAT \
   -textvariable AUDIOformat \
   -bg $entryBKGD \
   -width 9 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRaformat.labelAFORMAT2 \
   -text "$aRtext(labelAFORMAT2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## PACK the widgets in the '.fRaformat' frame:

pack .fRaformat.labelAFORMAT1 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRaformat.entryAFORMAT \
   -side left \
   -anchor w \
   -fill x \
   -expand 0

pack .fRaformat.labelAFORMAT2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+########################################################
## IN THE 'fRainterface' frame -- DEFINE 2 LABEL-ENTRY-LABEL
## triplets of widgets. Then PACK THEM.
##+########################################################

label .fRainterface.labelAINTERFACE1 \
   -text "$aRtext(labelAINTERFACE1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRainterface.entryAINTERFACE \
   -textvariable AUDIOinterface \
   -bg $entryBKGD \
   -width 9 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRainterface.labelAINTERFACE2 \
   -text "$aRtext(labelAINTERFACE2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label


label .fRainterface.labelACHANNELS1 \
   -text "$aRtext(labelACHANNELS1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRainterface.entryACHANNELS \
   -textvariable AUDIOchannels \
   -bg $entryBKGD \
   -width 3 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRainterface.labelACHANNELS2 \
   -text "$aRtext(labelACHANNELS2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label


## PACK the widgets in the '.fRainterface' frame:

pack .fRainterface.labelAINTERFACE1 \
     .fRainterface.entryAINTERFACE \
     .fRainterface.labelAINTERFACE2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRainterface.labelACHANNELS2 \
     .fRainterface.entryACHANNELS \
     .fRainterface.labelACHANNELS1 \
   -side right \
   -anchor e \
   -fill none \
   -expand 0


##+########################################################
## IN THE 'fRacodec' frame -- DEFINE a LABEL-ENTRY-LABEL
## triplet of widgets. Then PACK THEM.
##+########################################################

label .fRacodec.labelACODEC1 \
   -text "$aRtext(labelACODEC1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRacodec.entryACODEC \
   -textvariable AUDIOcodec \
   -bg $entryBKGD \
   -width 10 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRacodec.labelACODEC2 \
   -text "$aRtext(labelACODEC2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## PACK the widgets in the '.fRacodec' frame:

pack .fRacodec.labelACODEC1 \
     .fRacodec.entryACODEC \
     .fRacodec.labelACODEC2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+########################################################
## IN THE 'fRaother' frame -- DEFINE a LABEL-ENTRY pair
## of widgets. Then PACK THEM.
##+########################################################

label .fRaother.labelAOTHER \
   -text "$aRtext(labelAOTHER)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRaother.entryAOTHER \
   -textvariable AUDIOotherParms \
   -bg $entryBKGD \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

#   -width 30 \

## PACK the widgets in the '.fRaother' frame:

pack .fRaother.labelAOTHER \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRaother.entryAOTHER \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+########################################################
## IN THE '.fRotherhead' frame -- DEFINE 1 LABEL widget.
## Then PACK IT.
##+########################################################

label .fRotherhead.labelOTHERHEAD \
   -text "$aRtext(labelOTHERHEAD)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label \
   -bg $headBKGD

pack .fRotherhead.labelOTHERHEAD \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+########################################################
## IN THE '.fRthreads' frame -- DEFINE 1 LABEL-ENTRY-LABEL
## triplet of widgets. Then PACK THEM.
##+########################################################

label .fRthreads.labelTHREADS1 \
   -text "$aRtext(labelTHREADS1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

entry .fRthreads.entryTHREADS \
   -textvariable Nthreads \
   -bg $entryBKGD \
   -width 3 \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

label .fRthreads.labelTHREADS2 \
   -text "$aRtext(labelTHREADS2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label

## PACK the widgets in the '.fRthreads' frame:

pack .fRthreads.labelTHREADS1 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRthreads.entryTHREADS \
   -side left \
   -anchor w \
   -fill x \
   -expand 0

pack .fRthreads.labelTHREADS2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+########################################################
## IN THE 'fRguide' frame -- DEFINE 1 LABEL widget.
## Then PACK IT.
##+########################################################

label .fRguide.labelGUIDE \
   -text "$aRtext(labelGUIDE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief  flat \
   -bd $BDwidthPx_label \
   -bg $guideBKGD

## PACK the widgets in the 'fRguide' frame:

pack .fRguide.labelGUIDE \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


##+#####################################################################
## END OF SECTION TO DEFINE AND PACK THE GUI WIDGETS.
##+#####################################################################

##+#####################################################################
##+#####################################################################
## DEFINE BINDINGS:  button1-release bindings on CONTAINER radiobuttons
##+#####################################################################

## Bindings for the 'Container' radiobuttons.

bind .fRcontainer.radbuttMATROSKA  <ButtonRelease-1>  \
   {set_defaults_for_container matroska}

bind .fRcontainer.radbuttMPEG4  <ButtonRelease-1>  \
   {set_defaults_for_container mpeg4}

bind .fRcontainer.radbuttMPEG  <ButtonRelease-1>  \
   {set_defaults_for_container mpeg}

bind .fRcontainer.radbuttFLV  <ButtonRelease-1>  \
   {set_defaults_for_container flv}

bind .fRcontainer.radbuttAVI  <ButtonRelease-1>  \
   {set_defaults_for_container avi}

bind .fRcontainer.radbuttWEBM  <ButtonRelease-1>  \
   {set_defaults_for_container webm}

## Bindings for the 'ShowDetailedInputs' checkbutton.

bind .fRbuttons.chkbuttSHOWdetail  <ButtonRelease-1>  \
   {pack_detail_frames}


##+#####################################################################
##+#####################################################################
## DEFINE PROCEDURES:
##
##  'get_filename'   - called by the movie out-file 'Browse' button.
##                     (May not be needed, if the 'Browse' button is
##                      not implemented.)
##
##  'set_defaults_for_container' - called by bindings on the CONTAINER
##                                 radiobuttons.
##
##                     Sets defaults for the GUI widgets for a given
##                     container type.
##
##  'capture_movie'  - called by the 'LaunchMovieCapture' button.
##                     Launches the 'ffmpeg' program --- with user-selected
##                     recording parameters.
##
##  'play_movie'     - called by the 'PlayMovie' button.
##                     Launches a movie 'player' program.
##
##  'pack_detail_frames' - called by button1-release binding on the
##                         ShowDetail checkbutton
##
##  'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
##+#####################################################################
##+#####################################################################

##+#####################################################################
## PROC 'get_filename'
##+#####################################################################
## PURPOSE: To get a filename to use for the output movie file.
##
## CALLED BY: the 'Browse ...' button, if implemented.
##+#####################################################################

proc get_filename {} {

   ## INPUT globals:
   global env outDIR

   ## INPUT-OUTPUT globals:
   global ENTRYfilename

   ## Get a file name (possibly to make a mask).

   set fName [tk_getSaveFile -parent . -mustexist 0 \
      -title "Select an output filename for the movie file." \
      -initialdir "$outDIR" \
      -initialfile "$ENTRYfilename" ]

   ## FOR TESTING:
   #   puts "fName : $fName"

   ## Check if fName var is empty.

   if {"$fName" == ""} {return}

   ## Put $fName in ENTRYfilename. Reset the outDIR var.

   if {[file exists "$fName"]} {
      set ENTRYfilename "$fName"
      set outDIR [ get_chars_before_last / in "$ENTRYfilename" ]
   }

}
## END OF PROC 'get_filename'


##+###################################################################
## PROC 'get_chars_before_last' -
##+###################################################################
## INPUT:  A character and a string.
##         Note: The "in" parameter is there only for clarity.
##
## OUTPUT: Returns all of the characters in the string "strng" that
##         are BEFORE the last occurence of the characater "char".
##
## CALLED BY: proc 'get_img_filename'
##+##################################################################

proc get_chars_before_last { char in strng } {

   set endIDX [ expr [string last $char $strng ] - 1 ]
   set output [ string range $strng 0 $endIDX ]

   ## FOR TESTING:
   # puts "From 'get_chars_before_last' proc:"
   # puts "STRING: $strng"
   # puts "CHAR: $char"
   # puts "RANGE up to LAST CHAR - start: 0   endIDX: $endIDX"

   return $output

}
## END OF PROC 'get_chars_before_last'


##+#####################################################################
## PROC 'set_defaults_for_container'
##+#####################################################################
## PURPOSE: For a given container type, to set defaults for
##          the widgets on the GUI --- esp. the entry widgets.
##
## CALLED BY: a button1-release binding on the 'container' radiobuttons
##            and called once in the 'Additional GUI Initialization'
##            section at the bottom of this script.
##+#####################################################################

proc set_defaults_for_container { container } {

   ## FOR TESTING: (to dummy out this proc)
   #  return

   ## INPUT globals:
   global outDIR env

   ## OUTPUT globals:
   global ENTRYfilename ENTRYplayer \
      VIDEOsize VIDEOoffset VIDEOsource VIDEOformat  VIDEOrate \
      VIDEOcodec VIDEOotherParms AUDIOformat AUDIOinterface AUDIOchannels \
      AUDIOcodec AUDIOotherParms DELAYseconds Nthreads


   ############################
   ## FOR 'matroska' CONTAINER:
   ############################

   if {"$container" == "matroska"} {
      set ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.mkv"
      set ENTRYplayer "totem"
      set VIDEOsize "800x600"
      set VIDEOoffset "+10,30"
      set VIDEOsource ":0.0"
      set VIDEOformat "x11grab"
      set VIDEOrate "25"
      set VIDEOcodec "libx264"
      set VIDEOotherParms "-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset"
      set AUDIOformat "alsa"
      set AUDIOinterface "pulse"
      set AUDIOchannels "1"
      set AUDIOcodec "pcm_s16le"
      set AUDIOotherParms "-ar 22050 -ab 96k"
      set DELAYseconds "3"
      set Nthreads "1"
   }
   ## END OF   if {"$container" == "matroska"}


   #########################
   ## FOR 'mpeg4' CONTAINER:
   #########################

   if {"$container" == "mpeg4"} {
      set ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.mp4"
      set ENTRYplayer "totem"
      set VIDEOsize "800x600"
      set VIDEOoffset "+10,30"
      set VIDEOsource ":0.0"
      set VIDEOformat "x11grab"
      set VIDEOrate "25"
      set VIDEOcodec "libx264"
      set VIDEOotherParms "-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset"
      set AUDIOformat "alsa"
      set AUDIOinterface "pulse"
      set AUDIOchannels "1"
      set AUDIOcodec "libmp3lame"
      set AUDIOotherParms "-ar 44100 -ab 128k"
      set DELAYseconds "3"
      set Nthreads "1"
   }
   ## END OF   if {"$container" == "mpeg4"}


   #########################
   ## FOR 'mpeg4' CONTAINER:
   #########################

   if {"$container" == "mpeg"} {
      set ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.mpg"
      set ENTRYplayer "totem"
      set VIDEOsize "800x600"
      set VIDEOoffset "+10,30"
      set VIDEOsource ":0.0"
      set VIDEOformat "x11grab"
      set VIDEOrate "25"
      set VIDEOcodec "mpeg2video"
      set VIDEOotherParms "-bufsize 1835k"
      set AUDIOformat "alsa"
      set AUDIOinterface "pulse"
      set AUDIOchannels "1"
      set AUDIOcodec "libmp3lame"
      set AUDIOotherParms "-ar 44100 -ab 128k"
      set DELAYseconds "3"
      set Nthreads "1"
   }
   ## END OF   if {"$container" == "mpeg"}


   #########################
   ## FOR 'flv' CONTAINER:
   #########################

   if {"$container" == "flv"} {
      set ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.flv"
      set ENTRYplayer "totem"
      set VIDEOsize "800x600"
      set VIDEOoffset "+10,30"
      set VIDEOsource ":0.0"
      set VIDEOformat "x11grab"
      set VIDEOrate "25"
      set VIDEOcodec "libx264"
      set VIDEOotherParms "-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset"
      set AUDIOformat "alsa"
      set AUDIOinterface "pulse"
      set AUDIOchannels "1"
      set AUDIOcodec "libfaac"
      set AUDIOotherParms "-ar 44100 -ab 128k"
      set DELAYseconds "3"
      set Nthreads "1"
   }
   ## END OF   if {"$container" == "flv"}


   #########################
   ## FOR 'avi' CONTAINER:
   #########################

   if {"$container" == "avi"} {
      set ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.avi"
      set ENTRYplayer "totem"
      set VIDEOsize "800x600"
      set VIDEOoffset "+10,30"
      set VIDEOsource ":0.0"
      set VIDEOformat "x11grab"
      set VIDEOrate "25"
      set VIDEOcodec "mpeg4"
      set VIDEOotherParms ""
      set AUDIOformat "alsa"
      set AUDIOinterface "pulse"
      set AUDIOchannels "1"
      set AUDIOcodec "libmp3lame"
      set AUDIOotherParms "-ar 44100 -ab 128k"
      set DELAYseconds "3"
      set Nthreads "1"
   }
   ## END OF   if {"$container" == "avi"}


   #########################
   ## FOR 'webm' CONTAINER:
   #########################

   if {"$container" == "webm"} {
      ##
      ## REQUIRES TWO-PASSES WITH 'ffmpeg'??
      ##
      set ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.webm"
      set ENTRYplayer "totem"
      set VIDEOsize "800x600"
      set VIDEOoffset "+10,30"
      set VIDEOsource ":0.0"
      set VIDEOformat "x11grab"
      set VIDEOrate "25"
      set VIDEOcodec "libvpx"
      set VIDEOotherParms ""
      set AUDIOformat "alsa"
      set AUDIOinterface "pulse"
      set AUDIOchannels "1"
      set AUDIOcodec "vorbis"
      set AUDIOotherParms "-ar 44100 -ab 128k"
      set DELAYseconds "3"
      set Nthreads "1"

   }
   ## END OF   if {"$container" == "webm"}

}
## END OF PROC 'set_defaults_for_container'


##+#####################################################################
## PROC 'capture_movie'
##+#####################################################################
## PURPOSE: To startup the 'ffmpeg' program to capture the video and
##          audio from the computer screen and the audio circuitry ---
##          and make a movie file from that input.
##
## CALLED BY:  a click on the 'LaunchMovieCapture' button.
##+#####################################################################

proc capture_movie { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   ## INPUT globals:
   global  ENTRYfilename VIDEOsize VIDEOoffset VIDEOsource VIDEOformat VIDEOrate \
      VIDEOcodec VIDEOotherParms AUDIOformat AUDIOinterface AUDIOchannels \
      AUDIOcodec AUDIOotherParms DELAYseconds Nthreads CONTAINERformat DIRscripts

   set DELAYmillisecs [expr {$DELAYseconds * 1000}]

   after $DELAYmillisecs

   ###################################################################
   ## MAKE THE MOVIE FILE.
   ####################################################################
   ## SOME SYNTAX NOTES on running the 'ffmpeg' program via a Tcl 'exec':
   ####################################################################
   ## On page 105 of the 4th edition of 'Practical Programming in Tcl & Tk',
   ## is the following quote on the Tcl 'exec' command:
   ##
   ## "The 'exec' command runs programs from your Tcl script. For example:
   ##      set d [exec date]
   ## The standard output of the program is returned as the value of
   ## the 'exec' command. However, if the program writes to its standard
   ## error channel or exits with a nonzero status code, then 'exec'
   ## raises an error. If you do not care about the exit status, or you
   ## use a program that insists on writing to standard error, then you
   ## can use 'catch' to mask the errors:
   ##   catch {exec program arg arg} result"
   ##
   ## Unfortunately, running a player program in 'foreground' mode
   ## like this makes the button widgets on the GUI unavailable ---
   ## in particular, the 'Stop' button ... and the 'Help' button.
   ##
   ## A 'foreground' run per page 105 of 'Practical Programming in Tcl & Tk'.
   ## NOT USED, because it 'locks up' the GUI.
   #######################################################################
   ## On page 107 of the 4th edition of 'Practical Programming in Tcl & Tk',
   ## is the following quote on the Tcl 'exec' command and 'background' mode:
   ##
   ## "A trailing '&' causes the program to run in the background.
   ##  In this case, the process identifier is returned by the 'exec'
   ##  command. Otherwise, the 'exec' command blocks during execution
   ##  of the program, and the standard output of the program is the
   ##  return code of 'exec'."
   ##
   ## Page 83 of the same book says:
   ## "'catch' returns zero if there was no error caught,
   ##   or a nonzero error code if it did catch an error."
   ####################################################################
   ## A couple of examples of using a PID (process ID) with Tcl:
   ##
   ## catch {eval exec $feREADER_text \"$FULFILname\"  &} ProcessPID
   ##
   ## set RETcode [ catch {eval exec ${feDIR}/tkGUIs/shofil.tk \
   ##    "$FULFILname" &} ProcessPID ]
   ##
   ####################################################################
   ## An alternative form of trying 'exec':
   ##    exec  /bin/sh -c "$...."
   ####################################################################


   #########################################################################
   ## A 'background' run per page 107 of 'Practical Programming in Tcl & Tk'.
   ##
   ## We run 'ffmpeg' in an 'xterm' window so that messages can be seen
   ## by the user, and so that the user can type 'q' to stop the recording.
   #########################################################################

   ###########################################################################
   ## An attempt without using an external shell script:
   ##
   # set RETcode [ catch {eval exec /bin/sh -c \"xterm -bg black -fg white -hold -geometry 90x48+100+100 \
   #      -e ffmpeg -f $VIDEOformat -r $VIDEOrate -s $VIDEOsize \
   #      -i ${VIDEOsource}$VIDEOoffset -vcodec $VIDEOcodec $VIDEOotherParms \
   #      -f $AUDIOformat -i $AUDIOinterface -ac $AUDIOchannels -acodec $AUDIOcodec \
   #      -threads $Nthreads $ENTRYfilename \" &} CapturePID ]
   ###########################################################################
   ## 'eval' was used at one point here to avoid an 'unrecognized option' error
   ## when $VIDEOotherParms was appended to the 'ffmpeg' command.
   ###########################################################################
   ## From this particular order of the 'ffmpeg' parameters, I got the
   ## error: Unknown decoder 'libx264'
   ###########################################################################

   ##########################################################################
   ## In the following implementation using an external shell script
   ## (which includes the 'xterm' command),
   ## we *NEED* the double-quotes around several variables that may contain
   ## embedded spaces --- VIDEOotherParms, AUDIOotherParms, and ENTRYfilename.
   ##########################################################################

   set RETcode [ catch {exec \
      $DIRscripts/ffmpeg_monitorAndAudio_MovieCapture.sh $VIDEOsize $VIDEOoffset \
      $VIDEOsource $VIDEOformat $VIDEOrate $VIDEOcodec "$VIDEOotherParms" \
      $AUDIOformat $AUDIOinterface $AUDIOchannels $AUDIOcodec "$AUDIOotherParms" \
      $Nthreads $CONTAINERformat "$ENTRYfilename" &} CapturePID ]

   if {$RETcode != 0} {
      set ERRtext \
"Proc 'capture_movie' encountered an error on trying to make file
[file tail "$ENTRYfilename"]
in directory
[file dirname "$ENTRYfilename"]
using the 'ffmpeg' command.

RETcode: $RETcode
Message: $CapturePID
Stopping processing."
      popup_msgVarWithScroll .topErr "$ERRtext"
      return
   }
   ## END OF if {$RETcode != 0}

   ## FOR TESTING:
   if {0} {
       puts ""
       puts "***********************"
       puts "PROC 'capture_movie' ran 'ffmpeg' with"
       puts "ENTRYfilename: $ENTRYfilename"
       puts "and got"
       puts "RETcode: $REGcode"
       puts "CapturePID: $CapturePID"
       puts "***********************"
       puts ""
   }

}
## END OF PROC 'capture_movie'


##+#####################################################################
## PROC 'play_movie'
##+#####################################################################
## PURPOSE: To startup a user-selected media-player program on the
##          output filename specified on the GUI.
##
## CALLED BY:  a click on the 'PlayMovie' button.
##+#####################################################################

proc play_movie { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   global ENTRYfilename ENTRYplayer

   #######################################################
   ## Remove trailing and leading blanks (if any) from the
   ## user entry in the filename 'entry' widget.
   #######################################################

   set ENTRYfilename [string trim "$ENTRYfilename"]

   if {![file exists "$ENTRYfilename"]} {
      popup_msgVarWithScroll .topCount \
         "Filename in entry field does not exist."
      return
   }

   ###################################################################
   ## PLAY THE MOVIE FILE.
   ####################################################################
   ## SOME SYNTAX NOTES on running the player program via a Tcl 'exec':
   ####################################################################
   ## See the notes above in the 'capture_movie' proc.
   ####################################################################

   ## A 'foreground' run per page 105 of 'Practical Programming in Tcl & Tk'.
   ## NOT USED, because it 'locks up' the GUI.

   # catch {eval exec $ENTRYplayer "$ENTRYfilename"} CatchMsg


   ##########################################################################
   ## A 'background' run per page 105 of 'Practical Programming in Tcl & Tk'.
   ##
   ## We use 'eval' to avoid a 'not found' error when we append
   ## some parms (or a space) to the player command.
   ##########################################################################

   set RETcode [ catch {eval exec $ENTRYplayer "$ENTRYfilename" &} ViewerPID ]

   if {$RETcode != 0} {
      set ERRtext \
"Proc 'play_movie' encountered an error on trying to show file
[file tail "$ENTRYfilename"]
in directory
[file dirname "$ENTRYfilename"]
using command '$ENTRYplayer'.

RETcode: $RETcode
Message: $ViewerPID
Stopping processing."
      popup_msgVarWithScroll .topErr "$ERRtext"
      return
   }
   ## END OF if {$RETcode != 0}


   ## FOR TESTING:
   if {0} {
       puts ""
       puts "***********************"
       puts "PROC 'play_movie' ran the player program"
       puts "ENTRYplayer: $ENTRYplayer"
       puts "with input"
       puts "ENTRYfilename: $ENTRYfilename"
       puts "and got"
       puts "RETcode: $REGcode"
       puts "ViewerPID: $ViewerPID"
       puts "***********************"
       puts ""
   }


}
## END OF PROC 'play_movie'


##+#####################################################################
## PROC 'set_width_of_labels'
##+#####################################################################
## PURPOSE: To set a nice common width of the labels on the left of
##          each of the GUI sections:
##            - output/container
##            - video
##            - audio
##            - other
##          according to the font being used for labels.
##
## CALLED:  in the Additional GUI Initialization' section at the
##          bottom of this script.
##+#####################################################################

proc set_width_of_labels { } {

   ## FOR TESTING: (dummy out this proc)
   # return

   ## INPUT globals:
   global aRtext

   ## OUTPUT globals:
   global lengthOUTPUTprompts lengthVIDEOprompts lengthAUDIOprompts lengthOTHERprompts

   ## SET lengthOUTPUTprompts (in characters).

   set lengthOUTPUTprompts [string length "$aRtext(labelOUTFILE)"]
   set tempLENGTH [string length "$aRtext(labelPLAYER1)"]
   if {$tempLENGTH > $lengthOUTPUTprompts} {set lengthOUTPUTprompts $tempLENGTH}


   ## SET lengthVIDEOprompts (in characters).

   set lengthVIDEOprompts [string length "$aRtext(labelVSIZE1)"]
   set tempLENGTH [string length  "$aRtext(labelVOFFSET1)"]
   if {$tempLENGTH > $lengthVIDEOprompts} {set lengthVIDEOprompts $tempLENGTH}
   set tempLENGTH [string length  "$aRtext(labelVSOURCE1)"]
   if {$tempLENGTH > $lengthVIDEOprompts} {set lengthVIDEOprompts $tempLENGTH}
   set tempLENGTH [string length  "$aRtext(labelVCODEC1)"]
   if {$tempLENGTH > $lengthVIDEOprompts} {set lengthVIDEOprompts $tempLENGTH}
   set tempLENGTH [string length  "$aRtext(labelVOTHER)"]
   if {$tempLENGTH > $lengthVIDEOprompts} {set lengthVIDEOprompts $tempLENGTH}


   ## SET lengthAUDIOprompts (in characters).

   set lengthAUDIOprompts  [string length "$aRtext(labelAFORMAT1)"]
   set tempLENGTH [string length "$aRtext(labelAINTERFACE1)"]
   if {$tempLENGTH > $lengthAUDIOprompts} {set lengthAUDIOprompts $tempLENGTH}
   set tempLENGTH [string length "$aRtext(labelACODEC1)"]
   if {$tempLENGTH > $lengthAUDIOprompts} {set lengthAUDIOprompts $tempLENGTH}
   set tempLENGTH [string length "$aRtext(labelAOTHER)"]
   if {$tempLENGTH > $lengthAUDIOprompts} {set lengthAUDIOprompts $tempLENGTH}


   ## SET lengthOTHERprompts (in characters).

   set lengthOTHERprompts [string length "$aRtext(labelTHREADS1)"]
   # set tempLENGTH [string length "$aRtext(????)"]
   # if {$tempLENGTH > $lengthOTHERprompts} {set lengthOTHERprompts $tempLENGTH}


   ## Adjust for typical overestimate because of variable-width font
   ## used for the labels.

   set lengthOUTPUTprompts [expr {int(0.80 * $lengthOUTPUTprompts)}]
   set lengthVIDEOprompts  [expr {int(0.80 * $lengthVIDEOprompts)}]
   set lengthAUDIOprompts  [expr {int(0.85 * $lengthAUDIOprompts)}]
   set lengthOTHERprompts  [expr {int(0.85 * $lengthOTHERprompts)}]

}
## END OF PROC 'set_width_of_labels'


##+#####################################################################
## PROC 'pack_detail_frames'
##+#####################################################################
## PURPOSE: To pack the 'video', 'audio', and 'other' frames of
##          the GUI if the ShowDetail' checkbutton is ON.
##
##          Otherwise, 'forget' the 'video', 'audio', and 'other' frames.
##
## CALLED:  button1-release on a Show/Hide-Detail checkbutton on the GUI
##          AND, possibly, in the Additional GUI Initialization' section
##          at the bottom of this script.
##+#####################################################################

proc pack_detail_frames {} {

   global SHOWdetail0or1

   if {$SHOWdetail0or1 == 1} {

      pack .fRvideohead \
         -side top \
         -anchor nw \
         -fill x \
         -expand 0

      pack .fRvsize \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      pack .fRvoffset \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      pack .fRvsource \
         -side top \
         -anchor nw \
         -fill x \
         -expand 1

      pack .fRvcodec \
         -side top \
         -anchor nw \
         -fill x \
         -expand 1

      pack .fRvother \
         -side top \
         -anchor nw \
         -fill x \
         -expand 1

      pack .fRaudiohead \
         -side top \
         -anchor nw \
         -fill x \
         -expand 0

      pack .fRaformat \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      pack .fRainterface \
         -side top \
         -anchor nw \
         -fill x \
         -expand 1

      pack .fRacodec \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      pack .fRaother \
         -side top \
         -anchor nw \
         -fill x \
         -expand 1

      pack .fRotherhead \
         -side top \
         -anchor nw \
         -fill x \
         -expand 0

      pack .fRthreads \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      pack .fRguide \
         -side top \
         -anchor nw \
         -fill x \
         -expand 1
   } else {
      pack forget .fRvideohead .fRvsize .fRvoffset .fRvsource .fRvcodec \
         .fRvother .fRaudiohead .fRaformat .fRainterface .fRacodec  \
         .fRaother .fRotherhead .fRthreads .fRguide

   }
   ## END OF   if {$SHOWdetail0or1 == 1} 

}
## END OF PROC 'pack_detail_frames'


##+#############################################################
## PROC 'disable_enable_widgets'  (NOT USED YET)
##+#############################################################
## PURPOSE: Disable/enable widgets (esp. entry widgets)
##          based on ???.
##
## CALLED BY: Called in 'Additional GUI Initialization' section
##            at the bottom of the script --- and by
##            button1-release bindings on ???.
##+#############################################################

proc disable_enable_widgets {} {

   ## FOR TESTING: (to dummy out this proc)
   return

   global SEARCHmask SEARCHfiletype

   if {$SEARCHmask == 0} {
      .fRmask.labelFILEMASK configure -state disabled
      .fRmask.entryFILEMASK configure -state disabled
      .fRmask2.labelFILEMASKexamples configure -state disabled
   } else {
      .fRmask.labelFILEMASK configure -state normal
      .fRmask.entryFILEMASK configure -state normal
      .fRmask2.labelFILEMASKexamples configure -state normal
   }


   if {$SEARCHfiletype == 0} {
      .fRfiletype.labelFILETYPE configure -state disabled
      .fRfiletype.entryFILETYPE configure -state disabled
      .fRfiletype2.labelFILETYPEexamples configure -state disabled
   } else {
      .fRfiletype.labelFILETYPE configure -state normal
      .fRfiletype.entryFILETYPE configure -state normal
      .fRfiletype2.labelFILETYPEexamples configure -state normal
   }

}
## END OF proc 'disable_enable_widgets'


##+########################################################################
## PROC 'popup_msgVarWithScroll'
##+########################################################################
## PURPOSE: Report help or error conditions to the user.
##
##       We do not use focus,grab,tkwait in this proc,
##       because we use it to show help when the GUI is idle,
##       and we may want the user to be able to keep the Help
##       window open while doing some other things with the GUI
##       such as putting a filename in the filename entry field
##       or clicking on a radiobutton.
##
##       For a similar proc with focus-grab-tkwait added,
##       see the proc 'popup_msgVarWithScroll_wait' in a
##       3DterrainGeneratorExaminer Tk script.
##
## REFERENCE: page 602 of 'Practical Programming in Tcl and Tk',
##            4th edition, by Welch, Jones, Hobbs.
##
## ARGUMENTS: A toplevel frame name (such as .fRhelp or .fRerrmsg)
##            and a variable holding text (many lines, if needed).
##
## CALLED BY: 'help' button
##+########################################################################
## To have more control over the formatting of the message (esp.
## words per line), we use this 'toplevel-text' method,
## rather than the 'tk_dialog' method -- like on page 574 of the book
## by Hattie Schroeder & Mike Doyel,'Interactive Web Applications
## with Tcl/Tk', Appendix A "ED, the Tcl Code Editor".
##+########################################################################

proc popup_msgVarWithScroll { toplevName VARtext } {

   ## global fontTEMP_varwidth #; Not needed. 'wish' makes this global.
   ## global env

   # bell
   # bell

   #################################################
   ## Set VARwidth & VARheight from $VARtext.
   #################################################
   ## To get VARheight,
   ##    split at '\n' (newlines) and count 'lines'.
   #################################################

   set VARlist [ split $VARtext "\n" ]

   ## For testing:
   #  puts "VARlist: $VARlist"

   set VARheight [ llength $VARlist ]

   ## For testing:
   #  puts "VARheight: $VARheight"


   #################################################
   ## To get VARwidth,
   ##    loop through the 'lines' getting length
   ##     of each; save max.
   #################################################

   set VARwidth 0

   #############################################
   ## LOOK AT EACH LINE IN THE LIST.
   #############################################
   foreach line $VARlist {

      #############################################
      ## Get the length of the line.
      #############################################
      set LINEwidth [ string length $line ]

      if { $LINEwidth > $VARwidth } {
         set VARwidth $LINEwidth
      }

   }
   ## END OF foreach line $VARlist

   ## For testing:
   #   puts "VARwidth: $VARwidth"


   ###############################################################
   ## NOTE: VARwidth works for a fixed-width font used for the
   ##       text widget ... BUT the programmer may need to be
   ##       careful that the contents of VARtext are all
   ##       countable characters by the 'string length' command.
   ###############################################################


   #####################################
   ## SETUP 'TOP LEVEL' HELP WINDOW.
   #####################################

   catch {destroy $toplevName}
   toplevel  $toplevName

   # wm geometry $toplevName 600x400+100+50

   wm geometry $toplevName +100+50

   wm title     $toplevName "Note"
   # wm title   $toplevName "Note to $env(USER)"

   wm iconname  $toplevName "Note"


   #####################################
   ## In the frame '$toplevName' -
   ## DEFINE THE TEXT WIDGET and
   ## its two scrollbars --- and
   ## DEFINE an OK BUTTON widget.
   #####################################

   if {$VARheight > 10} {
      text $toplevName.text \
         -wrap none \
         -font fontTEMP_fixedwidth \
         -width  $VARwidth \
         -height $VARheight \
         -bg "#f0f0f0" \
         -relief raised \
         -bd 2 \
         -yscrollcommand "$toplevName.scrolly set" \
         -xscrollcommand "$toplevName.scrollx set"

      scrollbar $toplevName.scrolly \
         -orient vertical \
         -command "$toplevName.text yview"

      scrollbar $toplevName.scrollx \
         -orient horizontal \
         -command "$toplevName.text xview"
   } else {
      text $toplevName.text \
         -wrap none \
         -font fontTEMP_fixedwidth \
         -width  $VARwidth \
         -height $VARheight \
         -bg "#f0f0f0" \
         -relief raised \
         -bd 2
   }

   button $toplevName.butt \
      -text "OK" \
      -font fontTEMP_varwidth \
      -command  "destroy $toplevName"

   ###############################################
   ## PACK *ALL* the widgets in frame '$toplevName'.
   ###############################################

   ## Pack the bottom button BEFORE the
   ## bottom x-scrollbar widget,

   pack  $toplevName.butt \
      -side bottom \
      -anchor center \
      -fill none \
      -expand 0


   if {$VARheight > 10} {
      ## Pack the scrollbars BEFORE the text widget,
      ## so that the text does not monopolize the space.

      pack $toplevName.scrolly \
         -side right \
         -anchor center \
         -fill y \
         -expand 0

      ## DO NOT USE '-expand 1' HERE on the Y-scrollbar.
      ## THAT ALLOWS Y-SCROLLBAR TO EXPAND AND PUTS
      ## BLANK SPACE BETWEEN Y-SCROLLBAR & THE TEXT AREA.

      pack $toplevName.scrollx \
         -side bottom \
         -anchor center \
         -fill x  \
         -expand 0

      ## DO NOT USE '-expand 1' HERE on the X-scrollbar.
      ## THAT KEEPS THE TEXT AREA FROM EXPANDING.

      pack $toplevName.text \
         -side top \
         -anchor center \
         -fill both \
         -expand 1
   } else {
      pack $toplevName.text \
         -side top \
         -anchor center \
         -fill both \
         -expand 1
   }


   #####################################
   ## LOAD MSG INTO TEXT WIDGET.
   #####################################

   ##  $toplevName.text delete 1.0 end

   $toplevName.text insert end $VARtext

   $toplevName.text configure -state disabled

}
## END OF PROC 'popup_msgVarWithScroll'


##+########################
## END of PROC definitions.
##+########################
## Set HELPtext var.
##+########################


set HELPtext \
"** HELP for this 'Computer-Monitor-and-Computer-Audio Movie-Capture Utility **

This utility provides a GUI for recording video and audio from
a computer, using the 'ffmpeg' program to make a movie file
from the video and audio inputs.

The video is recorded from the activity on the video monitor, and
the audio is recorded from the audio board/circuitry of the computer.

The operation can be as simple as clicking on the 'LaunchMovieCapture'
button --- and then clicking on the 'PlayMovie' button, after the movie
file has been created --- if you take the initial defaults.

(A separate 'ffmeg' utility will be provided for recording video from
a web cam, instead of from the computer monitor --- along with recording
audio from audio circuitry of the computer.)

Currently, this utility is set to capture video data in 'x11grab' format.
So the capture requires the X11 windowing system and will only capture
video data known to X11. For example, this utility may not capture
OpenGL data in various windows on the desktop.

*********************
Movie File Parameters
*********************

Note that a movie file is composed of 3 formats:

- the container format       (Examples: matroska, mpeg4, mpeg, avi, webm)
- the video 'codec' format   (Examples: H.264, Mpeg4, Mpeg2, xvid, vp8)
- the audio 'codec' format   (Examples: mp3, pcm, aac, vorbis)

'codec' is an abbreviation for (en)code-and-decode.

This GUI utility does 'encoding' to make the movie file.

By default, the GUI for this utility is set to the 'Matroska'
container format --- and the GUI is defaulted to video and
audio 'codec' formats that are supported by that container format.

Also video and audio parameters are provided on the GUI that are
compatible with those video and audio 'codecs'.

However, the knowledgeable user (knowledgeable in the mysterious
ways of the 'ffmpeg' program) may wish to override some of the
video and audio parameters (including the 'codecs') --- so most
of the parameters on the GUI are changeable by the user.

When the user has the parameters ready (for simplicity, the user
may simply take the defaults), a click on the 'LaunchMovieCapture'
buttons starts up the 'ffmpeg' command.

******************
The Control Window (a.k.a. the 'ffmpeg' window or the 'xterm' window)
******************

This utility runs the 'ffmpeg' command in a popup 'xterm' window,
so that the user can see messages coming from the movie-making program,
ffmpeg --- and so that the user can stop the recording by typing 'q'
in the popup (control) window.

Since the user is recording the video activity on the computer monitor,
the user may have to minimize some windows out of the way --- including
the GUI window of this utility --- and the 'xterm' (stop-control) window,
after it pops up.

NOTE: MINIMIZE the 'xterm' window; do NOT close it. If you close it,
the 'ffmpeg' program is killed.

It would not really hurt if the user changed some parameters
and the 'ffmpeg' program failed. The 'ffmpeg' window will
show error messages that may be helpful in determining a solution.

The 'ffmpeg' window is 'held open' --- even when the 'ffmpeg'
program ends (normally or abnormally) --- so that the user can
examine messages from the program. When done with the messages,
simply close the 'ffmpeg' window.


**********************
Playing the Movie File
**********************

You can specify a 'player' program for the movie file in an entry
field near the top of the GUI. After it appears that a movie file
has been created (with the output filename specified in a filename
entry field on the GUI), you can try playing the movie file by
clicking on the 'PlayMovie' button.


*********************************
Post-Processing of the Movie File
*********************************

There is a 'delay' parameter on the GUI that allows the user to
specify a 'wait time' (in seconds). That 'delay time' is the time
between a click on the 'LaunchMovieCapture' button and the instant
that the 'ffmpeg' program is started (which is when the 'xterm'
window pops up).

The 'delay time' provides the user time to setup for the video and
audio recording. For example, the user will probably want to minimize
the GUI window of this utility so that it does not appear in
the movie.

However, it is quite likely that it will be hard to avoid some
video or audio 'artifacts' at the beginning and at the end
of the movie. Typically, the 'ffmpeg'/'xterm' window will be
seen briefly at the beginning of the movie (before the user
minimizes it) --- and the 'ffmpeg'/'xterm' window will be
seen at the end of the movie (when the user opens it and
types 'q').

The user may want to do some post-processing of the movie file
--- such as clipping of some seconds from the beginning and the end.

The 'ffmpeg' program can be used for things like clipping and
cropping of movie files. And there are interactive video
editors that can be used to edit the movie file.

I plan to make a separate GUI utility that makes it easy
to use the 'ffmpeg' program to do some non-interactive movie
file editing such as
   - extracting 'clips' from a movie
   - cropping the bottom/top/left/right of the movie image
   - extracting the audio from the movie
   - adding audio to a soundless movie file
   - and maybe a few more movie editing deeds.


***********************************
Some 'ffmpeg' Movie Capture Tidbits (gathered from the internet)
***********************************

REFERENCE: http://ubuntuforums.org/archive/index.php/t-1392026.html
           'HOWTO: Proper Screencasting on Linux' (as seen in 2011)

\"...we capture audio from pulse (pulseaudio sound server) and encode it
to *'lossless'* raw PCM with 2 audio channels (stereo). Then, we grab a
video stream from x11 at a frame rate of 30 and a size of 1024×768
from the display :0.0 and encode it to *'lossless'* h264 using libx264.
... The resulting streams will be muxed in a Matroska container (.mkv).\"

I have high-lighted the quotes around 'lossless' because when analog
data is recorded in digital form, there is automatically some loss of
information.
   
\"Using '-threads 0' means automatic thread detection.\"


NOTE: You might want to record one audio channel, with '-ac 1'.
      AND
      You might want use a frame rate less than 30, say 25 or even less.
      These changes may reduce size of the output file significantly.

----------------------------
Audio parms - pulse/alsa/oss:
----------------------------

   \"Most recent Linux distributions have PulseAudio installed by default,
    but if your distribution does not use the pulseaudio sound system,
    try replacing '-f alsa -ac 2 -i pulse' with something like
    '-f alsa -ac 2 -i hw:0,0'. Many users of this guide reported
    success with the above options. You might have to change the
    0,0 to match that of your sound device. You could also try
    '-f alsa -ac 2 -i /dev/dsp'.  Other users reported success with
    '-f oss -ac 2 -i /dev/dsp'.
    Basically there are many ways to do it, and it depends on your
    system's sound configurations and hardware.\"

-----------------------------
Controlling Pulse audio input:
-----------------------------

\"To control PulseAudio input (e.g. capture application audio instead of mic)
 install 'pavucontrol'. Start recording with 'ffmpeg'. Start 'pavucontrol'.
 Go to the 'Recording' tab and you'll find 'ffmpeg' listed there.
 Change audio capture from 'Internal Audio Analog Stereo' to
 'Monitor of Internal Audio Analog Stereo'.
 Now it should record system and application audio instead of microphone.

 This setting will be remembered. The next time you want to capture with
 'ffmpeg', it will automatically start recording system audio.
 If you want to revert this, use 'pavucontrol' again to change back to
 microphone input.\"

 Message you may get if 'pavucontrol' is not installed:

$ pavucontrol
The program 'pavucontrol' is currently not installed.
You can install it by typing: 
    sudo apt-get install pavucontrol
pavucontrol: command not found

NOTE: You have to start an audio recording applicaton before using
'pavucontrol' to set the audio source. Otherwise, the 'Recording'
panel of 'pavucontrol' shows the message 'No application is currently
recording audio'.

---------------
On pause/resume:
---------------

\"Pause/resume screencasting isn't possible with ffmpeg yet, but you can
 use 'mkvmerge' to achieve the same result. You can install this program
 from your distribution's package management system under the package
 name 'mkvtoolnix', or download it from the official website
 http://www.bunkus.org/videotools/mkvtoolnix/. 'mkvmerge' allows you to
 concatenate mkv files with identically-encoded streams to a single file.
 Meaning that if you want to make a pause from screencasting, you'll
 just stop recording part 1, then start recording part 2 as another file,
 and finally concatenate (i.e. add) these 2 parts into a single screencast
 ready for final compression. You can do this for as many parts as
 you like. Example:
     mkvmerge -o complete.mkv part1.mkv +part2.mkv +part3.mkv +part4.mkv
 This command pruduces a video file named 'complete.mkv' that has all
 the parts put together in the order they were specified into on the
 command line.
 However, note that all the parts you want to concatenate must have
 exactly the same size/framerate/encoding parameters, otherwise it
 won't work. You can't add files with different encoding options to
 each other.\"

-----------------------
Hiding the mouse cursor:
-----------------------

 \"To hide the mouse cursor, add '+nomouse' after ':0.0' to look like this:
  :0.0+nomouse \"  (thanks to FakeOutdoorsman)


********************************
Changing the Defaults on the GUI
********************************

The defaults that appear on the GUI are set in a 'proc' named
'set_defaults_for_container'. You can find that proc in this
Tk script and change the defaults as you wish.

The initial, default output directory for the movie file is
set near the bottom of the script by the statement:
    set outDIR \"/tmp\"
You can edit the script to change that location.


**************************************
Sample output from an 'ffmpeg' command  (from an 'x11grab' recording)
**************************************

If a user is having problems in getting a successful recording, the following
output from a successful 'ffmpeg' recording run may be helpful.

The lines after the 'frame=' line were output after 'q' was typed.

Some 'ffmpeg' build info is at the top of the messages from 'ffmpeg'.
The recording messages start at the first 'x11grab' line:

FFmpeg version SVN-r19352-4:0.5+svn20090706-2ubuntu2.3,
  Copyright (c) 2000-2009 Fabrice Bellard, et al.
  configuration: --extra-version=4:0.5+svn20090706-2ubuntu2.3 --prefix=/usr
  --enable-avfilter --enable-avfilter-lavf --enable-vdpau --enable-bzlib --enable-libgsm
  --enable-libschroedinger --enable-libspeex --enable-libtheora --enable-libvorbis
  --enable-pthreads --enable-zlib --disable-stripping --disable-vhook --enable-gpl
  --enable-postproc --enable-swscale --enable-x11grab --enable-libdc1394
  --extra-cflags=-I/build/buildd/ffmpeg-0.5+svn20090706/debian/include
  --enable-shared --disable-static
  libavutil     49.15. 0 / 49.15. 0
  libavcodec    52.20. 0 / 52.20. 0
  libavformat   52.31. 0 / 52.31. 0
  libavdevice   52. 1. 0 / 52. 1. 0
  libavfilter    0. 4. 0 /  0. 4. 0
  libswscale     0. 7. 1 /  0. 7. 1
  libpostproc   51. 2. 0 / 51. 2. 0
  built on Mar 31 2011 18:50:18, gcc: 4.4.1
\[x11grab @ 0x8bb3700\]device: :0.0+10,30 -> display: :0.0 x: 10 y: 30 width: 800 height: 600
\[x11grab @ 0x8bb3700\]shared memory extension  found
Input #0, x11grab, from ':0.0+10,30':
  Duration: N/A, start: 1401482597.517237, bitrate: 384000 kb/s
    Stream #0.0: Video: rawvideo, rgb32, 800x600, 384000 kb/s, 25 tbr, 1000k tbn, 25 tbc
\[alsa @ 0x8bbfc70\]capture with some ALSA plugins, especially dsnoop, may hang.
Input #1, alsa, from 'pulse':
  Duration: N/A, start: 1401482596.951060, bitrate: N/A
    Stream #1.0: Audio: pcm_s16le, 44100 Hz, mono, s16, 705 kb/s
Output #0, matroska, to '/tmp/blaze_screen_capture_movie.mkv':
    Stream #0.0: Video: libx264, yuv420p, 800x600, q=10-51, 200 kb/s, 90k tbn, 25 tbc
    Stream #0.1: Audio: pcm_s16le, 22050 Hz, mono, s16, 352 kb/s
Stream mapping:
  Stream #0.0 -> #0.0
  Stream #1.0 -> #0.1
\[libx264 @ 0x8bcda50\]using cpu capabilities: MMX2 SSE2Fast FastShuffle SSEMisalign LZCNT
\[libx264 @ 0x8bcda50\]profile High 4:4:4 Predictive, level 3.1
Press \[q\] to stop encoding
frame=   42 fps=  4 q=861008.9 Lsize=     705kB time=11.44 bitrate= 505.0kbits/s    
video:208kB audio:493kB global headers:0kB muxing overhead 0.556447%
\[libx264 @ 0x8bcda50\]slice I:1     Avg QP: 0.00  size:120718
\[libx264 @ 0x8bcda50\]slice P:41    Avg QP: 0.00  size:  2247
\[libx264 @ 0x8bcda50\]mb I  I16..4: 59.4%  0.0% 40.6%
\[libx264 @ 0x8bcda50\]mb P  I16..4: 31.6%  0.0%  0.0%  P16..4:  0.6%  0.0%  0.0% 
  0.0%  0.0%    skip:67.8%
\[libx264 @ 0x8bcda50\]coded y,uvDC,uvAC intra:3.3% 2.5% 2.5% inter:0.5% 0.0% 0.0%
\[libx264 @ 0x8bcda50\]kb/s:1013.6

******************
More 'ffmpeg' info
******************

For more information on 'ffmpeg', use the commands 'man ffmpeg' and 'ffmpeg -h'.
To see the supported input formats, use 'ffmpeg -formats'.
The main web site is at ffmpeg.org.

The 'ffmpeg -h' help points out the basic format in using the many 'ffmpeg'
options:

 ffmpeg \[\[infile options\] -i infile\]... \{\[outfile options\] outfile\}...

Even with this guideline, it can be quite challenging to formulate a non-trivial
'ffmpeg' command in such a way as to avoid terminating errors.

The output from 'ffmpeg -formats' can be rather overpowering. It is more than
400 lines --- with a lot of audio and image formats as well as movie formats
--- and no separation of audio and video codecs --- and no clear designation
of 'container' formats. So I provide the following list of 'container formats'
followed by 'video codecs', followed by 'audio codecs' --- ones that could be
useful in making movie files.

In the following, 'D' indicates that 'ffmpeg' will decode the format and
'E' indicates that 'ffmpeg' will encode the format. (This utility is
mainly concerned with 'E', encoding --- although it does decode an
X11 image format.)

SOME MOVIE CONTAINER FORMATS:

  E 3g2             3GP2 format
  E 3gp             3GP format
 DE asf             ASF format
 DE avi             AVI format
 DE flv             FLV format
 DE matroska        Matroska file format
  E mov             MOV format
  E mp4             MP4 format
 DE mpeg            MPEG-1 System format
 DE ogg             Ogg
  E vcd             MPEG-1 System format (VCD)
  E vob             MPEG-2 PS format (VOB)

SOME MOVIE-VIDEO SOURCE FORMATS:

 D  video4linux     Video4Linux device grab
 D  video4linux2    Video4Linux2 device grab
 D  x11grab         X11grab


SOME VIDEO CODECS:

 DEVSD  flv             Flash Video (FLV)
  EV    libx264         libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
 DEVSDT mpeg1video      MPEG-1 video
 DEVSDT mpeg2video      MPEG-2 video
 DEVSDT mpeg4           MPEG-4 part 2
 DEV D  svq1            Sorenson Vector Quantizer 1
 D VSD  svq3            Sorenson Vector Quantizer 3
  EV    libtheora       libtheora Theora
 D V    theora          Theora
 DEVSD  wmv1            Windows Media Video 7
 DEVSD  wmv2            Windows Media Video 8
 D V    wmv3            Windows Media Video 9
  EV    libxvid         libxvidcore MPEG-4 part 2

SOME AUDIO CODECS:

  EA    libfaac         libfaac AAC (Advanced Audio Codec)
 D A    libfaad         libfaad AAC (Advanced Audio Codec)
  EA    libmp3lame      libmp3lame MP3 (MPEG audio layer 3)
 D A    mp3             MP3 (MPEG audio layer 3)
 D A    mp1             MP1 (MPEG audio layer 1)
 DEA    mp2             MP2 (MPEG audio layer 2)
 DEA    pcm_s16le       PCM signed 16-bit little-endian
 DEA    vorbis          Vorbis
  EA    libvorbis       libvorbis Vorbis

There are many PCM formats --- signed/unsigned, big/little endian, floating,
8/16/24/32/64 bit. But the 'pcm_s16le' format is probably the most common.

The fields preceding the 'ffmpeg' format and codec names have the following
meanings:

    D  Decoding available
    E  Encoding available
V/A/S  Video/audio/subtitle codec
    S  Codec supports slices
    D  Codec supports direct rendering
    T  Codec can handle input truncated at random locations instead of
       only at frame boundaries
"


##+######################################################
## ADDITIONAL GUI INITIALIZATION section.
##+######################################################

##+#############################################################
## Set an initial output directory for the output movie file.
##+#############################################################

set outDIR "/tmp"

##+##################################################
## Use the variable of the 'container' radiobuttons
## to set an initial choice of the container format.
##+##################################################

set CONTAINERformat "matroska"
# set CONTAINERformat "mpeg4"
# set CONTAINERformat "mpeg"
# set CONTAINERformat "flv"
# set CONTAINERformat "avi"
# set CONTAINERformat "webm"

##+###########################################
## Set the GUI widgets according to an initial
## setting of the container format.
##+###########################################

set_defaults_for_container $CONTAINERformat

##+#############################################################
## Set the widths of the prompts (labels) on the left of the GUI
## --- in the 'output', 'video', 'audio', and 'other' sections.
##+#############################################################

set_width_of_labels

## For the 'output' section:

.fRoutfile.labelOUTFILE configure -width $lengthOUTPUTprompts
.fRplayer.labelPLAYER1  configure -width $lengthOUTPUTprompts

## For the 'video' section:

.fRvsize.labelVSIZE1     configure -width $lengthVIDEOprompts
.fRvoffset.labelVOFFSET1 configure -width $lengthVIDEOprompts
.fRvsource.labelVSOURCE1 configure -width $lengthVIDEOprompts
.fRvcodec.labelVCODEC1   configure -width $lengthVIDEOprompts
.fRvother.labelVOTHER    configure -width $lengthVIDEOprompts

## For the 'audio' section:

.fRaformat.labelAFORMAT1 configure -width $lengthAUDIOprompts
.fRainterface.labelAINTERFACE1 configure -width $lengthAUDIOprompts
.fRacodec.labelACODEC1   configure -width $lengthAUDIOprompts
.fRaother.labelAOTHER    configure -width $lengthAUDIOprompts

## For the 'other' section:

.fRthreads.labelTHREADS1 configure -width $lengthOTHERprompts


##+####################################################
## Disable/enable widgets according to intial settings.
## (Not needed, for now.)
##+####################################################

# disable_enable_widgets


##+#############################################################
## Get the directory that this Tk script is in. That will be the
## directory that any 'external' utility shell or Tk script
## should be in.
##+#############################################################

## FOR TESTING:
#  puts "argv0: $argv0"

# set DIRscripts "."
# set DIRscripts "[pwd]"
# set DIRscripts "$env(HOME)/apps/tkUtils"
  set DIRscripts "[file dirname $argv0]"


Shell script (called by the Tk script) :

And here is the code for the shell script called by this Tk script.

Having the 'ffmpeg' call in a shell script instead of embedded in the Tk script facilitates testing and debugging. For example, this script can be tested independently of the Tk script.

In fact, this shell script could be modified to serve as a 'hard-coded' means of recording computer sessions.

You can put this script in the same directory with the Tk script. The Tk script includes some code (involving the 'argv0' variable) to determine the location of the shell script by extracting the name of the directory in which the Tk script lies.

 Code for shell-script 'ffmpeg_monitorAndAudio_MovieCapture.sh' :

#!/bin/sh
##
## SCRIPT NAME: ffmpeg_monitorAndAudio_MovieCapture.sh
##
##+#######
## PURPOSE:
##  This script fruns the 'ffmpeg' command after being provided with
##  about 15 'ffmpeg' parameters passed to this script.
##
##  This shell script is meant to be issued from the Tk GUI 'wrapper' script
##  --- 'monitorAndAudio_MovieCapture_ffmpeg_FrontEnd.tk'.
##  That Tk script is to get parameters for the 'ffmpeg' command --- for the
##  purpose of recording the monitor screen and audio from a computer
##  into a movie file.
##
##  The 'ffmpeg' parameters are passed into this script via *positional*
##  parameters in the order indicated below.
##
##  Having the 'ffmpeg' call in a shell script instead of embedded in the
##  Tk script facilitates testing and debugging. For example, this
##  script can be tested independently of the Tk script. ('ffmpeg'
##  is very sensitive to the order of the input parameters, as well
##  as sensitive to the container-video-audio formats selected ---
##  as evidenced by the many appeals for help on internet forums.)
##
##+######
## INPUTS:
##
## Here are example default parameters for 'ffmpeg' from the Tk script,
## preceded by the variable names used in the Tk script:
##
##    Var01:  VIDEOsize "800x600"
##    Var02:  VIDEOoffset "+10,30"
##    Var03:  VIDEOsource ":0.0"
##    Var04:  VIDEOformat "x11grab"
##    Var05:  VIDEOrate "25"
##    Var06:  VIDEOcodec "libx264"
##    Var07:  VIDEOotherParms "-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset"
##    Var08:  AUDIOformat "alsa"
##    Var09:  AUDIOinterface "pulse"
##    Var10:  AUDIOchannels "1"
##    Var11:  AUDIOcodec "pcm_s16le"
##    Var12:  AUDIOotherParms "-ar 22050 -ab 96k"
##    Var13:  Nthreads "1"
##    Var14:  CONTAINERformat "matroska"
##    Var15:  ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.mkv"
##
## In this script, we will put those parameters in shell script variables
## using the same variable names as above --- except that we will
## use 'OUTfile' instead of 'ENTRYfilename' and 'CONTAINfmt' instead of
## 'CONTAINERformat'.
##
##+#########################################################################
## REFERENCE: http://ubuntuforums.org/archive/index.php/t-1392026.html
##            "HOWTO: Proper Screencasting on Linux" (as seen in 2011)
##
## "...we capture audio from pulse (pulseaudio sound server) and encode it
## to *'lossless'* raw PCM with 2 audio channels (stereo). Then, we grab a
## video stream from x11 at a frame rate of 30 and a size of 1024×768
## from the display :0.0 and encode it to *'lossless'* h264 using libx264.
## ... The resulting streams will be muxed in a Matroska container (.mkv)."
##+#########################################################################
## MAINTENANCE HISTORY:
## Started by: Blaise Montandon 2014may29 
## Updated by: Blaise Montandon 2014may30 Added the 'CONTAINfmt' variable.
##                                        Re-ordered the 'ffmpeg' parms to
##                                        avoid the MISLEADING error message:
##                                        Unknown decoder 'libx264'
##+#########################################################################

## FOR TESTING: (to show statements as they execute)
#   set -x

VIDEOsize="$1"
VIDEOoffset="$2" 
VIDEOsource="$3"
VIDEOformat="$4"
VIDEOrate="$5"
VIDEOcodec="$6"
VIDEOotherParms="$7"
AUDIOformat="$8"
AUDIOinterface="$9"
AUDIOchannels="$10"
AUDIOcodec="$11"
AUDIOotherParms="$12"
Nthreads="$13"
CONTAINfmt="$14"
OUTfile="$15"

## FOR TESTING of this script without the Tk wrapper:
## (For stand-alone testing, change 'if test 1 = 0' to 'if test 1 = 1'.)

if test 1 = 0
then

   VIDEOsize="800x600"
   # VIDEOsize="1024x768"

   VIDEOoffset="+10,30"
   # VIDEOoffset="+0,0"

   VIDEOsource=":0.0"

   VIDEOformat="x11grab"

   VIDEOrate="25"
   # VIDEOrate="30"

   VIDEOcodec="libx264"
   # VIDEOcodec="xvid"
   # VIDEOcodec="libvpx"
   # VIDEOcodec="mpeg1video"
   # VIDEOcodec="flv"

   VIDEOotherParms="-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset"
   # VIDEOotherParms=""

   AUDIOformat="alsa"
   # AUDIOformat="oss"

   AUDIOinterface="pulse"
   # AUDIOinterface="hw:0,0"
   # AUDIOinterface="/dev/dsp"

   AUDIOchannels="1"
   # AUDIOchannels="2"

   AUDIOcodec="pcm_s16le"
   # AUDIOcodec="libmp3lame"
   # AUDIOcodec="libfaac"
   # AUDIOcodec "vorbis"

   AUDIOotherParms="-ar 22050 -ab 96k"
   # AUDIOotherParms="-ar 44100 -ab 128k"

   Nthreads="1"
   # Nthreads="2"
   # Nthreads="0"  ## auto-detect, max CPUs (not advisable?)

   CONTAINfmt="matroska"
   # CONTAINfmt="mpeg4"
   # CONTAINfmt="mpeg"
   # CONTAINfmt="flv"
   # CONTAINfmt="avi"
   # CONTAINfmt="webm"

   OUTfile="/tmp/${USER}_screen_capture_movie.mkv"

fi

## FOR TESTING:
#   echo "OUTfile: $OUTfile"


## Simply exit if there is no output filename passed to this script.

if test "$OUTfile" = ""
then
   exit
fi


##+##########################################################
## Prepare to use the filename to hold the movie.
## Make sure we start with a new (empty) output file.
##+##########################################################

rm -f "$OUTfile"


##+#######################################################
## Call on the 'ffmpeg' command, which puts the movie
## in file "$OUTfile".
##
## We run ffmpeg in an 'xterm' so that we can see its messages
## and the user can stop the recording by opening the xterm
## window and typing 'q' in the window.
##
## We could move the 'xterm' call into the calling Tk script.
##
## We do not use '&' to run this process in the background,
## but the Tk script that calls this script issues the call
## as a background process, rather than foreground.
##+#######################################################

## FOR TESTING: (to show statements as they execute)
#   set -x

xterm -bg black -fg white -hold -geometry 90x48+100+100 -e ffmpeg \
   -f $VIDEOformat -r $VIDEOrate -s $VIDEOsize -i ${VIDEOsource}$VIDEOoffset \
   -f $AUDIOformat -ac $AUDIOchannels -i $AUDIOinterface \
   -vcodec $VIDEOcodec $VIDEOotherParms \
   -acodec $AUDIOcodec $AUDIOotherParms \
   -threads $Nthreads "$OUTfile"

## The following order of parameters (all video, then all audio) gave 
## the puzzling error message:  Unknown decoder 'libx264'
##
## (Puzzling because I knew that the 'libx264' coder was available,
##  because another order of the parameters in a different script worked.
##  This is proof that 'ffmpeg' can give VERY MISLEADING error messages.)
##
##   ffmpeg -f $VIDEOformat -r $VIDEOrate -s $VIDEOsize \
##   -i ${VIDEOsource}$VIDEOoffset -vcodec $VIDEOcodec $VIDEOotherParms \
##   -f $AUDIOformat -i $AUDIOinterface -ac $AUDIOchannels -acodec $AUDIOcodec \
##   -threads $Nthreads "$OUTfile"
##
## It appears that 'ffmpeg' parameters should be grouped such that
## ALL the 'input' parameters (video AND audio) are to be specified BEFORE
## the 'output' (in particular, codec) parameters.


INSTALLING THE SCRIPTS:

The Tk script and the shell script could be put in a sub-directory of the user's home directory, such as $HOME/apps/tkMovieCaptureComputerMonitor.

Then the user can use their desktop system (such as Gnome or KDE) to set up the Tk script as an icon on the desktop.

Then, whenever the user wants to record a computer session, the user can click on the icon to startup this 'front end' to the 'ffmpeg' command.

LINK TO A MOVIE CAPTURE EXAMPLE

Here is a link to a movie capture that I did with this GUI. [2]

It is a capture of an 800x600 portion a computer monitor screen as I demonstrate the 'dynamic-font-resizing' of the font-selector that I published at the page titled YAFSG - Yet Another Font Selector GUI --- as I move the 'scale' widget on that font-selector GUI.

This video indicates the impact of the recording process on other processing on the computer. The expansion and contraction of the font-selector window goes in 'fits and starts' in this video. When I am not recording a movie, the expansion and contraction goes quite smoothly --- and the font resizes quite smoothly.

So let the movie-recorder-person be aware of the impact. For example, if a person records the action during a video game, the frame-rate of the video game will probably be adversely affected.

SOME POSSIBLE ENHANCEMENTS

I have no major enhancements that I can think of for the Tk script at this time. However, in the future, I may find that I may want/need to change some default video or audio or 'other' parameters for some of the container formats.

And I may find that it is worthwhile implementing the WEBM format.

Rather than try to make this Tk script also work for capturing video from a web cam (instead of from the computer monitor), I plan to work on a similar script to capture movies from a web cam --- and from the audio circuitry of a computer.

I also plan to work on at least one other 'front end' for 'ffmpeg' --- for example, for clipping, cropping, audio-extraction, audio-addition, and some other movie file editing functions.

IN CONCLUSION

As I have said on several other code-donation pages on this wiki ...

There's a lot to like about a utility that is 'free freedom' --- that is, no-cost and open-source so that you can modify/enhance/fix it without having to wait for someone else to do it for you (which may be never).

A BIG THANK YOU to Ousterhout for starting Tcl-Tk, and a BIG THANK YOU to the Tcl-Tk developers and maintainers who have kept the simply MAH-velous 'wish' interpreter going.

uniquename 2014jun30 - UPDATE - 'ffmpeg' or 'avconv'

I should point out that members of the 'ffmpeg' development project went through a heated difference of opinion, and a result was that the 'avconv' program was started as a 'fork' of the 'ffmpeg' program. (This happened in the 2010-2013 time frame.)

Some rather vague details of the 'meltdown' can be seen at the 'ffmpeg' web site [3] and the 'libav' web site [4] (home of the 'avconv' program). Also see Wikipedia [5].

One outcome of this 'fork' is that around 2013, the Debian Linux project started providing the 'avconv' package instead of the 'ffmpeg' package. And the two most popular Linux 'distros' --- Linux Mint and Ubuntu --- (which are based on Debian Linux) started providing the 'avconv' package instead of 'ffmpeg'.

At this time (2014), the command-line parameters used by 'ffmpeg' and 'avconv' have not changed much. So, if you have 'avconv', not 'ffmpeg', you can change the places where 'ffmpeg' is called (in the scripts above) to 'avconv'.

There have been some changes in command-line parameters in more recent versions of 'ffmpeg' (changes between 2009 and 2014). For example, in recent examples of 'ffmpeg' commands at internet forums, you may see '-c:a' used instead of '-acodec' (for audio codec). If a parameter like '-acodec' no longer works, you can simply change the occurrences of '-acodec' to '-c:a', in the calls to 'ffmeg'/'avconv' in the code above. The same goes for most of the other 'ffmpeg'/'avconv' parameters used in this utility.

This is just one more example of the 'wonderfulness' of using Tcl-Tk scripts (and shell scripts) for making GUI's --- easy modification to accomodate 'variations'.