Movie Edit Utility - Clip, Crop, Convert, etc. - a front-end for the 'ffmpeg' command

uniquename - 2014jun18

I recently (2014may,jun) published 2 utilities for recording a movie

  • from a COMPUTER MONITOR and the audio system of a computer
  • from a WEB CAM and the audio system of a computer

at two pages titled

Movie Capture from Computer Monitor-and-Audio - a front-end for the 'ffmpeg' command

and

Movie Capture from Computer Webcam-and-Audio - a front-end for the 'ffmpeg' command

I had mentioned on these pages that I planned 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.

Such a movie-editing utility (a front-end for the 'ffmpeg' command) is the subject of this page.

---

THE GOALS

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

*** Provide entry widgets for an input movie file and an output media file --- along with a 'Browse' button to easily select the input file.

*** Provide a listbox widget by which to select the edit operation to be performed --- CLIP, CROP, CONVERT, etc. Also provide PROPERTIES-IN and PROPERTIES-OUT options to query the properties of the input and output files --- after they have been selected and created, respectively.

*** Provide entry widgets for the approximately 8-plus parameters that can be specified to 'ffmpeg' to specify the container-video-audio parameters for creating the output movie file. Provide working defaults for the parameters.

*** Provide a 'ExecOption' button to start the execution of the option that the user selected from the listbox.

*** Provide an entry widget to allow the user to specify a movie-player program with which to play either the input or the output media 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 the 2 'movie-capture' utilities that I posted here, I made a 'text-sketch' for the GUI for this 'movie-edit' 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.
  --------------------------------------------------------------------------------------
  Movie Clip, Crop, Etc. Utility - a front-end for the 'ffmpeg' command
  [window title]
  --------------------------------------------------------------------------------------

  [On the left of the following frames will be a Tk 'listbox' widget in frame '.fRleft'.
   The following frames will be contained in frame '.fRright'.]

  '.fRright'
   SubFrame
    names
     |
     V

 .fRbuttons   {Exit} {Help} {ExecOption} {PlayOutMovie} {PlayInMovie}  X MoreMovieOutParms (video,audio,other)

 .fRmsg       Select a movie-processing option from the listbox on the left. Then provide the processing
              parameters at the prompts in the 'ExecOption Parameters' section that appears below.
              An 'xterm' window will appear when processing starts. You can see processing messages in
              that window. When processing is finished, use the 'PlayMovie' button to show the movie.
              [This initial message in a label widget may be changed when the 'Exec' button is clicked.]

 .fRinfile    Input movie filename : $env(HOME)/input_movie.mkv_______________________  {Browse...}

              --------------------------------------------------------------------------------------
 .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)

 .fRoutfile   Output movie filename : /tmp/$env(USER)_output_movie.mkv___________________

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

              --------------------------------------------------------------------------------------
 .fRoptsHead   ExecOption Parameters:   [This label may dynamically change according to option selected.
                                        Examples: '  (CLIP)' or  ' (CROP)' may be added after 'Parameters:'.]
              --------------------------------------------------------------------------------------

 .fRexecOpts  [The sub-frames and widgets that appear here
               will depend on the listbox line currently selected.
               An example for CLIP is seen in an image below.]

 .fRvidaud    [This frame and its following subframes are shown if
               the 'MoreMovieOutParms' checkbuttons is set ON.]

  '.fRvidaud'
   SubFrame
    names
     |
     V
              --------------------------------------------------------------------------------------
 .fRvideoHead Video-out parameters:
              --------------------------------------------------------------------------------------

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

 .fRvrate     Video-out rate (frames/sec): 25_ Examples: 25  30  24 ...

 .fRvcodec    Video-out coder: libx264_____ Examples: libx264  mpeg4  mpeg1video  flv  ...

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

              -------------------------------------------------------------------------------------
 .fRaudioHead Audio-out parameters:
              -------------------------------------------------------------------------------------

 .fRachannels Audio-out Channels: 1_ Examples: 1  2

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

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

              --------------------------------------------------------------------------------------
 .fRother     Other output recording 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. You may minimize the 'xterm' window while processing, if you do not
              want to monitor the processing messages. When processing is done, the terminal does not close,
              so that you can examine messages. 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

   6 'button' widgets
  32 'label'  widgets (many are for entry fields)
  14 'entry'  widgets
   1 'checkbutton' widget
   6 'radiobutton' widgets (in one group)
   1 'listbox' widget (with scrollbars)
   0 'scale'  widgets
   0 'canvas' widgets
   0 'text' widgets

All but the 'label' widgets provide operating parameters/options in this utility. Hence there are about 6+14+1+6 = 27 options on this utility --- not counting the user-selectable options in the listbox (approximately another 12, eventually).

---

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 'semi-interactive' editing of movie files with 'ffmpeg' as simple as a few clicks --- on a listbox and an 'Exec' button and a 'Play' button --- and perhaps entering a few characters in a couple of entry widgets.

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.

movieClipCropEtc_ffmpegFrontEndGUI_initial_926x307.jpg

The basic operatiing sequence is

1) click on the listbox to select an option, like CLIP.

2) enter a couple of option parameters in the widgets that pop up in the 'ExecOption Parameters' section/frame of the GUI.

3) optionally use the 'PROPERTIES-IN' and/or the 'PlayInMovie' options to get information needed to set some editing parameters

4) optionally change the 'container' format for the output file, via the radiobuttons on the GUI --- and optionally use the 'MoreMovieOutParms' checkbutton to reveal the video-audio-other parameters that can be changed.

5) click on the 'ExecOption' button to launch the 'ffmpeg' job.

6) when the output is complete, use the 'PlayOutMovie' button (and perhaps the 'PROPERTIES-OUT' option) on the output media file.

(You can change some of the initial values on the GUI, like the initial container-format, 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 'MoreMovieOutParms' checkbutton at the top of the GUI.

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

movieClipCropEtc_ffmpegFrontEndGUI_CLIPopts_showVidAudParms_927x681.jpg

---

When the 'ExecOption' button is clicked and an 'ffmpeg' edit operation starts, an 'xterm' window pops up that shows the messages coming from the 'ffmpeg' program during its operation. Here is an example from a CROP run.

movieClipCropEtc_ffmpegFrontEnd_xtermForCROPrun_screenshot_548x651.jpg

Some 'ffmpeg' build info is at the top of the messages from 'ffmpeg' --- up to the 'Input #0' line.

The lines between the 'Input #0' line and the 'frame=' line are the initial messages that 'ffmpeg' puts out before starting the encoding of the output file.

The lines after the 'frame=' line are 'summary' lines that were output at the end of the edit run.

The 'frame=' line is updated 'in place' during the encoding.

The string 'time=12.64' in the 'frame=' line indicates that the output file that was created is about 12 seconds in duration.

The string 'frame= 387' in the 'frame=' line indicates that the output file that was created contains 387 image frames.

(The warning message above the 'frame=' line

   width or height not divisible by 16 (320x120), compression will suffer

is not as serious as it sounds. The resulting output movie file usually looks as good as the input file.)

Note the prompt 'File ... already exists. Overwrite? (y/N)' under the 'Stream' lines. I had done a previous run and the output file remained. I simply entered 'y' at the prompt, and 'ffmpeg' processing resumed.

---

THE CONTAINER FORMATS

For the 'movie capture' utilities, I tested the 5 active (non-grayed-out) 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 output movie file creation.

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-edit' 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 input/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 'normal' to 'bold' (if you have a screen resolution bigger than 1024x768) --- or change '-slant' from 'roman' to 'italic' --- or change the font sizes. 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

  'get_INfilename'               - called by the movie in-file 'Browse' button.

  'get_chars_before_last'        - called by the proc 'get_INfilename'.

  'set_defaults_for_container'   - called by bindings on the CONTAINER
                                   radiobuttons.

                                   Sets defaults for the video-audio-other
                                   GUI widgets, for a given container type.

  'loadOptsFrame_perListboxSelection' - called by a click on the listbox.

                                 Calls on a 'show_*_opts' proc depending on
                                 the listbox line (movie-exec-operation) selected.

                                 Example proc name: 'show_CLIP_opts'

  'exec_movie_operation'       - called by a click on the 'ExecOption' button.

                                 Calls on a 'set_*_cmd' proc depending on
                                 the listbox line (media-file-operation) selected.

                                 Example proc name: 'set_CLIP_cmd'

                                 Then executes the 'ffmpeg' command string built by
                                 the 'set_*_cmd' proc --- in an 'xterm' window.

  --------------------------------------------------------------------------------------
  For each ExecOption added to the listbox, a 'show_*_opts' proc and a 'set_*_cmd' proc
  should be provided --- like the following.
           (And calls will need to be added to the 2 procs above:
            'loadOptsFrame_perListboxSelection' and 'exec_movie_operation'.)
  --------------------------------------------------------------------------------------
  'show_CLIP_opts'            - called by a button1-release binding on the listbox,
                                which calls the 'loadOptsFrame_perListboxSelection' proc.

                                Loads 'clip' frames and widgets into an 'execOpts' frame.

  'set_CLIP_cmd'              - called by the 'exec_movie_operation' proc which is called
                                by the 'ExecOption' button.

                                Sets an 'ffmpeg' command string for CLIPPING --- to be
                                used in the proc 'exec_movie_operation'.

  --------------------------------------------------------------------------------------
  'show_CROP_opts'            - called by a button1-release binding on the listbox,
                                which calls the 'loadOptsFrame_perListboxSelection' proc.

                                Loads 'crop' frames and widgets into an 'execOpts' frame.

  'set_CROP_cmd'              - called by the 'exec_movie_operation' proc which is called
                                by the 'ExecOption' button.

                                Sets an 'ffmpeg' command string for CROPPING --- to be
                                used in the proc 'exec_movie_operation'.

  --------------------------------------------------------------------------------------
  'show_PROPSin_opts'         - called by a button1-release binding on the listbox,
                                which calls the 'loadOptsFrame_perListboxSelection' proc.

                                Loads 'PROPSin' frames and widgets into an 'execOpts' frame.

  'set_PROPSin_cmd'           - called by the 'exec_movie_operation' proc which is called
                                by the 'ExecOption' button.

                                Sets an 'ffmpeg' command string for showing properties
                                of the input media file. The command string is to be used
                                in the proc 'exec_movie_operation'.

  --------------------------------------------------------------------------------------
  'show_PROPSout_opts'        - called by a button1-release binding on the listbox,
                                which calls the 'loadOptsFrame_perListboxSelection' proc.

                                Loads 'PROPSout' frames and widgets into an 'execOpts' frame.

  'set_PROPSout_cmd'          - called by the 'exec_movie_operation' proc which is called
                                by the 'ExecOption' button.

                                Sets an 'ffmpeg' command string for showing properties
                                of the output media file. The command string is to be used
                                in the proc 'exec_movie_operation'.

  --------------------------------------------------------------------------------------
  'show_CONVERT_opts'         - called by a button1-release binding on the listbox,
                                which calls the 'loadOptsFrame_perListboxSelection' proc.

                                Loads 'crop' frames and widgets into an 'execOpts' frame.

  'set_CONVERT_cmd'           - called by the 'exec_movie_operation' proc which is called
                                by the 'ExecOption' button.

                                Sets an 'ffmpeg' command string for CONVERTING the input
                                media file to a new container and/or video and/or audio
                                format. The command string is to be used in the proc
                                'exec_movie_operation'.

  --------------------------------------------------------------------------------------

  'play_movie_out'           - called by the 'PlayOutMovie' button. Launches a movie
                               'player' program on the output movie file.

  'play_movie_in'            - called by the 'PlayInMovie' button. Launches a movie
                               'player' program on the input movie file.

  'set_width_of_labels'      - called in the 'Additional GUI Initialization'
                               section at the bottom of this script.

                               Sets 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.

  'pack_more_outparms_frame'  - called by button1-release binding on the
                                'MoreMovieOutParms' checkbutton.

                                Shows the 'video', 'audio', and 'other' frames
                                of the GUI if the 'MoreMovieOutParms' checkbutton
                                is ON. OR, 'forgets' the frame containing
                                the 'video', 'audio', and 'other' frames.

  'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
                                Also used to show various warning/error/info
                                messages to the user.

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

whether or not the 'video-audio-other' parameter frames are showing. That is, whether or not the 'MoreMovieOutParms' checkbutton is ON or OFF.


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 'Motorcycles Gone Wild' videos.


 Code for Tk script 'movieClipCropEtc_ffmpeg_FrontEnd.tk' :
#!/usr/bin/wish -f
##
## Tk SCRIPT NAME: movieClipCropEtc_ffmpeg_FrontEnd.tk
##
##+#######################################################################
## PURPOSE:  This Tk script provides a GUI for using the 'ffmpeg' program
##           to process MOVIE files in various ways --- Clip, Crop, etc.
##           In other words, this is a MULTI-PURPOSE movie processing
##           utility.
##
##           The GUI offers multiple movie-processing options via a
##           Tk 'listbox' widget that contains processing-type indicators
##           such as 'CLIP', 'CROP', 'PROPERTIES-IN', 'PROPERTIES-OUT',
##           'EXTRACT-AUDIO', 'REMOVE-AUDIO', 'ADD-AUDIO', etc.
##
##           For a given user-selected processing option, an 'execOpts'
##           Tk 'frame' widget in the GUI is filled with parameter-prompting
##           widgets suited to the option selected.  For example:
##
##           - If CLIP is selected, entry fields are provided to enter
##             a start-time and a duration-time for the clipping operation.
##
##           - If CROP is selected, radiobutton widgets are provided to
##             specify which side to crop (top, bottom, left, right)
##             and an entry field is provided to enter how many pixels to crop.
##
##           In addition, there are radiobutton widgets by which the
##           user can select a 'container' format for the output movie file.
##
##           And there is a stack of about 10 frames (the stack is defaulted to hidden)
##           that contain widgets by which the user can specify the video and
##           audio formats and their parameters --- for making the output movie file.
##           These widgets contain defaults that are determined by the
##           'container' format that is selected.
##
##           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, documentation found via
##           web searches.
##
##           Various 'label' widgets on the GUI provide examples to indicate
##           to the user the typical parameter values that may be entered in
##           'entry' widgets.
##
##           Also the GUI is meant to provide defaults for the movie-making
##           container-video-audio parameters that are known to work (provided the
##           necessary video and audio and container codec libraries are available.)
##
##           The options available to the user are indicated
##           by the following 'sketch' of the GUI:
##
## ---------------------------------------------------------------------
##
## THE SKETCH CONVENTIONS 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.
##
##  --------------------------------------------------------------------------------------
##  Movie Clip, Crop, Etc. Utility - a front-end for the 'ffmpeg' command
##  [window title]
##  --------------------------------------------------------------------------------------
##
##  [On the left of the following frames will be a Tk 'listbox' widget in frame '.fRleft'.
##   The following frames will be contained in frame '.fRright'.]
##
##  '.fRright'
##   SubFrame
##    names
##     |
##     V
##
## .fRbuttons   {Exit} {Help} {ExecOption} {PlayOutMovie} {PlayInMovie}  X MoreMovieOutParms (video,audio,other)
##
## .fRmsg       Select a movie-processing option from the listbox on the left. Then provide the processing
##              parameters at the prompts in the 'ExecOption Parameters' section that appears below.
##              An 'xterm' window will appear when processing starts. You can see processing messages in
##              that window. When processing is finished, use the 'PlayMovie' button to show the movie.
##              [This initial message in a label widget may be changed when the 'Exec' button is clicked.]
##
## .fRinfile    Input movie filename : $env(HOME)/input_movie.mkv_______________________  {Browse...}
##
##              --------------------------------------------------------------------------------------
## .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)
##
## .fRoutfile   Output movie filename : /tmp/$env(USER)_output_movie.mkv___________________
##
## .fRplayer    Player for the movie file: totem________ Examples: totem  gmplayer  mplayer  ffplay  vlc
##
##              --------------------------------------------------------------------------------------
## .fRoptsHead   ExecOption Parameters:   [This label may dynamically change according to option selected.
##                                        Examples: '  (CLIP)' or  ' (CROP)' may be added after 'Parameters:'.]
##              --------------------------------------------------------------------------------------
##
## .fRexecOpts  [The sub-frames and widgets that appear here
##               will depend on the listbox line currently selected.
##               A couple of examples, for CLIP and CROP, are shown below.]
##
## .fRvidaud    [This frame and its following subframes are shown if
##               the 'MoreMovieOutParms' checkbuttons is set ON.]
##
##  '.fRvidaud'
##   SubFrame
##    names
##     |
##     V
##              --------------------------------------------------------------------------------------
## .fRvideoHead Video-out parameters:
##              --------------------------------------------------------------------------------------
##
## .fRvidsize   Video-out size: 1024x768____ Examples: 640x480  800x600  1024x768 ...
##
## .fRvrate     Video-out rate (frames/sec): 25_ Examples: 25  30  24 ...
##
## .fRvcodec    Video-out coder: libx264_____ Examples: libx264  mpeg4  mpeg1video  flv  ...
##
## .fRvother    Other video-out parms: -vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset_______
##
##              -------------------------------------------------------------------------------------
## .fRaudioHead Audio-out parameters:
##              -------------------------------------------------------------------------------------
##
## .fRachannels Audio-out Channels: 1_ Examples: 1  2
##
## .fRacodec    Audio-out codec: pcm_s16le__ Examples: pcm_s16le  libmp3lame  libfaac  vorbis
##
## .fRaother    Other audio-out parms: -ar 22050 -ab 96k_________________________________________________
##
##              --------------------------------------------------------------------------------------
## .fRother     Other output recording 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. You may minimize the 'xterm' window while processing, if you do not
##              want to monitor the processing messages. When processing is done, the terminal does not close,
##              so that you can examine messages. 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 (not counting the widgets in the
## 'execOpts' frame) consists of ABOUT:
##
##   6 'button' widgets
##  32 'label'  widgets (many are for entry fields)
##  14 'entry'  widgets
##   1 'checkbutton' widget
##   6 'radiobutton' widgets (in one group)
##   1 'listbox' widget (with scrollbars)
##   0 'scale'  widgets
##   0 'canvas' widgets
##   0 'text' widgets
##
##+##########################################################
## SOME SAMPLE SUB-FRAMES and WIDGETS IN FRAME 'execOpts':
##
##  'execOpts'
##   SubFrame
##    names
##     |
##     V
## FOR CLIPPING:
##
## .fRclip1      Start time (hrs:min:sec): 00:01:23__   Duration (hrs:min:sec):  00:00:22__
##
## FOR CROPPING:
##
## .fRcrop1      Side to crop:  O bottom   O top   O left   O right
##
## .fRcrop2      Pixels to crop: 40__   X Pad with black
##
##+#####################################################################
## CALLED BY:  This script could be put in a sub-directory of the
##             users home directory, such as
##                   $HOME/apps/tkEditMovies.
##
##             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, whenever the user wants to edit a movie, 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, text-array-for-labels-etc, win-size-control).
##
##  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 frames:
##   '.fRleft'   to hold a listbox widget with xy scrollbars.
##   '.fRright'  to hold the following sub-frames:
##
##   '.fRright.fRbuttons'     for Exit, Help, Exec, Play buttons.
##   '.fRright.fRmsg'         for a label widget (for messages).
##   '.fRright.fRinfile'      for label-entry-button widgets.
##   '.fRright.fRoutHead'     for a label widget (for a heading).
##   '.fRright.fRcontainer'   for a label and several radiobutton widgets.
##   '.fRright.fRoutfile'     for label-entry widgets.
##   '.fRright.fRplayer'      for label-entry-label widgets.
##   '.fRright.fRoptsHead'    for a label widget.
##   '.fRright.fRexecOpts'    for 1 or more sub-frames.
##   '.fRright.fRvidaud'      for the following sub-frames:
##
##   '.fRright.fRvidaud.fRvideoHead'   for a label widget (for a heading).
##   '.fRright.fRvidaud.fRvidsize'     for label-entry-label widgets.
##   '.fRright.fRvidaud.fRvrate'       for label-entry-label widgets.
##   '.fRright.fRvidaud.fRvcodec'      for label-entry-label widgets.
##   '.fRright.fRvidaud.fRvother'      for label-entry widgets.
##   '.fRright.fRvidaud.fRaudioHead'   for a label widget (for a heading).
##   '.fRright.fRvidaud.fRachannels'   for label-entry widgets.
##   '.fRright.fRvidaud.fRacodec'      for label-entry widgets.
##   '.fRright.fRvidaud.fRaother'      for label-entry widgets.
##   '.fRright.fRvidaud.fRotherHead'   for a label widget (for a heading).
##   '.fRright.fRvidaud.fRthreads'     for label-entry-label widgets.
##   '.fRright.fRvidaud.fRguide'       for a label widget (for usage info).
##
##       This is about 24 frames and sub-frames, not counting a variable
##       number of sub-frames in 'fRexecOpts'.
##       Most of these sub-frames are 1 character high.
##
##  1b) Pack ALL these frames and sub-frames --- except 'fRvidaud'.
##
##      (We use 'show_*_opts' procs to replace the 'fRexecOpts' frame according to
##       the user's listbox selection, and we use a 'pack_more_outparms_frame'
##       proc to pack or pack-forget 'fRvidaud' according to whether the
##      'MoreMovieOutParms' checkbutton is ON or OFF.)
##
##  2) Define & pack all widgets in these frames -- basically going through
##     frames & their interiors in  left-to-right, top-to-bottom order:
##
##  3) Define bindings:  See BINDINGS section below.
##
##     SOME bindings are:
##
##     - A button1-release binding on the listbox widget will trigger a proc
##       that shows the appropriate widgets in the 'fRexecOpts' frame.
##
##     - A button1-release binding on the 'MoreMovieOutParms' checkbutton widget
##       will trigger a proc that shows/hides the 'fRvidaud' frame.
##
##  4) Define procs:   See the PROCS section below.
##
##     SOME of the procs are:
##
##  'get_INfilename'             - called by the movie in-file 'Browse' button.
##
##  'set_defaults_for_container' - called by button1-release bindings on the CONTAINER
##                                 radiobuttons. Also called in the 'Additional GUI
##                                 Initialization' at the bottom of this script.
##
##                                 Sets defaults for the video-audio-other widgets
##                                 for a given output container type.
##
##  'loadOptsFrame_perListboxSelection' - called by a click on the listbox.
##
##                                 Calls on a 'show_*_opts' proc (below) depending on
##                                 the listbox line (movie-operation) selected.
##
##                                 Example 'show_*_opts' proc name: 'show_CLIP_opts'
##
##  'exec_movie_operation'       - called by a click on the 'ExecOption' button.
##
##                                 Calls on a 'set_*_cmd' proc depending on
##                                 the listbox line (movie-operation) selected.
##
##                                 Example 'set_*_cmd' proc name: 'set_CLIP_cmd'
##
##                                 Then executes the 'ffmpeg' command built by the
##                                 'set_*_cmd' proc --- in an 'xterm' window.
##
##--------------------------------------------------------------------------------------
## For each ExecOption added to the listbox, a 'show_*_opts' proc and a 'set_*_cmd' proc
## should be provided --- like the following.
##           (And calls to the 2 new procs will need to be added, in two procs:
##            'loadOptsFrame_perListboxSelection' and 'exec_movie_operation'.)
##--------------------------------------------------------------------------------------
##
##  'show_CLIP_opts'            - called by a button1-release binding on the listbox.
##
##                                Loads frames and widgets into the 'execOpts' frame.
##
##  'set_CLIP_cmd'              - called by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string --- with user-selected
##                                parameters for clipping and with parameters for creating
##                                the output movie file.
##
##--------------------------------------------------------------------------------------
##  'show_CROP_opts'            - called by a button1-release binding on the listbox
##
##                                Loads frames and widgets into the 'execOpts' frame.
##
##  'set_CROP_cmd'              - called by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string --- with user-selected
##                                parameters for cropping and with parameters for creating
##                                the output movie file.
##--------------------------------------------------------------------------------------
##
##  'play_movie_out'            - called by the 'PlayOutMovie' button. Launches a movie
##                                'player' program on the output movie file.
##
##  'play_movie_in'             - called by the 'PlayInMovie' button. Launches a movie
##                                'player' program on the input movie file.
##
##  'pack_more_outparms_frame'  - called by button1-release binding on the
##                                'MoreMovieOutParms' checkbutton --- to show/hide
##                                the video-audio-other parameter frames.
##
##  'popup_msgVarWithScroll'    - called by 'Help' button to show the HELPtext var.
##                                Also used to show various warning/error/info
##                                messages to the user.
##
##  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 2014jun10 Started development, on Ubuntu 9.10,
##                                        based on a couple of Tk scripts that
##                                        contain most of the frames and widgets
##                                        that are needed:
##                           'webcamAndAudio_MovieCapture_ffmpeg_FrontEnd.tk'
##                                        and '3DmodelGenerator.tk'
## Updated by: Blaise Montandon 2014jun11 Got the GUI up for first time. Was
##                                        getting burned out on the extent of
##                                        this script. Took a break for a few days.
## Updated by: Blaise Montandon 2014jun16 Touched up the GUI and started filling
##                                        out the procs.
##+#######################################################################

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

wm title    . "Movie Clip, Crop, Etc. Utility - a front-end for the 'ffmpeg' command"
wm iconname . "MovieEdit"

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 listboxBKGD "#ffffff"
# set scaleBKGD   "#f0f0f0"

##+########################################################
## 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.
##
## 'weight' can be 'bold' or 'normal'.
## 'slant'  can be 'roman' or 'italic'.
##+########################################################

font create fontTEMP_varwidth \
   -family {comic sans ms} \
   -size -12 \
   -weight normal \
   -slant roman

font create fontTEMP_SMALL_varwidth \
   -family {comic sans ms} \
   -size -10 \
   -weight normal \
   -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 -12 \
   -weight normal \
   -slant roman

font create fontTEMP_SMALL_fixedwidth  \
   -family {liberation mono} \
   -size -10 \
   -weight normal \
   -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.


## LISTBOX widget geom settings:

set initListboxWidthChars 25
set initListboxHeightChars 15
set BDwidthPx_listbox 2
## We use '-relief sunken' for the 'listbox' widget.


## 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 '.fRright.fRbuttons' frame:

set aRtext(buttonEXIT)    "Exit"
set aRtext(buttonHELP)    "Help"
set aRtext(buttonEXEC)    "ExecOption"
set aRtext(buttonPLAYOUT) "PlayOutMovie"
set aRtext(buttonPLAYIN)  "PlayInMovie"
set aRtext(chkbuttMOREoutparms) "MoreMovieOutParms (video,audio,other)"

## For '.fRright.fRmsg' frame:

set aRtext(labelMSG) \
"Select a movie-processing option from the listbox on the left. Then provide the processing parameters
at the prompts in the 'ExecOption Parameters' section that appears below. For most options, an 'xterm'
window will appear when processing starts. You can see processing messages in that window.  When
processing is finished, use the 'PlayOutMovie' button to show the movie. Use 'Help' button for details."

## For '.fRright.fRinfile' frame:

set aRtext(labelINFILE) "Input  movie  filename :"
set aRtext(buttBROWSE)  "Browse..."

## For '.fRright.fRoutHead' frame:

set aRtext(labelOUTHEAD) "Output File Parameters:"

## For '.fRright.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 '.fRright.fRoutfile' frame:

set aRtext(labelOUTFILE) "Output  movie  filename :"

## For '.fRright.fRplayer' frame:

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

## For '.fRright.fRoptsHead' frame:

set aRtext(labelOPTShead) "ExecOption Parameters:"

## For '.fRright.fRexecOpts' frame:

set aRtext(labelEXECopts) \
"SELECT AN OPTION FROM THE LISTBOX. Appropriate parameter prompts will appear here."

## For '.fRright.fRvidaud.fRvideoHead' frame:

set aRtext(labelVIDEOHEAD) "Video-out recording parameters:"

## For '.fRright.fRvidaud.fRvsize' frame:

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

## For '.fRright.fRvidaud.fRvrate' frame:

set aRtext(labelVRATE1) "Video-out Rate:"
set aRtext(labelVRATE2) "Examples: 25  30  24 ..."

## For '.fRright.fRvidaud.fRvcodec' frame:

set aRtext(labelVCODEC1) "Video-out coder:"
set aRtext(labelVCODEC2) "Examples: libx264  mpeg4  mpeg2video  flv ...    "

## For '.fRright.fRvidaud.fRvother' frame:

set aRtext(labelVOTHER) "Other video-out parms:"


## For '.fRright.fRvidaud.fRaudioHead' frame:

set aRtext(labelAUDIOHEAD) "Audio-out recording parameters:"

## For '.fRright.fRvidaud.fRaformat' frame:

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

## For '.fRright.fRvidaud.fRacodec' frame:

set aRtext(labelACODEC1) "Audio-out coder:"
set aRtext(labelACODEC2) "Examples: pcm_s16le  libmp3lame  libfaac  vorbis"

## For '.fRright.fRvidaud.fRaother' frame:

set aRtext(labelAOTHER) "Other audio-out parameters:"


## For '.fRright.fRvidaud.fRotherHead' frame:

set aRtext(labelOTHERHEAD) "Other output recording parameters:"

## For '.fRright.fRvidaud.fRthreads' frame:

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


## For '.fRright.fRvidaud.fRguide' frame:

set aRtext(labelGUIDE) \
"NOTE: For most ExecOptions, this utility runs 'ffmpeg' in an 'xterm' window. Startup and coding messages
from 'ffmpeg' can be seen in that window. You may minimize the 'xterm' window while processing, if you
do not want to monitor the processing messages. When processing is done, the 'xterm' window does not close,
so that you can examine messages. The output file, if good, can be shown in a movie player, that you
specify above.  See 'Help' for details."

##+#############################
## For the 'execOpts' sub-frames:
##+#############################

## For the CLIP option:

set aRtext(labelSTARTtime)    "Start time (hrs:min:sec):"
set aRtext(labelDURATIONtime) "Duration (hrs:min:sec):"


## For the CROP option:

set aRtext(labelCROPside)     "Side to crop:"
set aRtext(radbuttCROPbottom) "bottom"
set aRtext(radbuttCROPtop)    "top"
set aRtext(radbuttCROPleft)   "left"
set aRtext(radbuttCROPright)  "right"

set aRtext(labelCROPpixels) "Pixels to crop:"
set aRtext(chkbuttPAD)  "Pad with black"

## For the PROPERTIES-IN option:

set aRtext(labelPROPERTIESin) \
"**CLICK THE 'ExecOption' BUTTON.** The PROPERTIES of the INPUT file will be shown in a popup window."


## For the PROPERTIES-OUT option:

set aRtext(labelPROPERTIESout) \
"**CLICK THE 'ExecOption' BUTTON.** The PROPERTIES of the OUTPUT file are to be shown in a popup window."


## For the CONVERT option:

set aRtext(labelCONVERT) \
"Set 'CONVERT' parms with the 'container' radiobuttons and the 'MoreOutMovieParms' widgets.
OR take the defaults for the container-video-audio-other parameters."
set aRtext(chkbuttRESIZE)  "Change the SIZE of the video"
set aRtext(chkbuttRERATE)  "Change the RATE of the video"


## For the AUDIO-EXTRACT option:  (later)


## For the AUDIO-REMOVE option:  (later)


## For the AUDIO-ADD option:  (later)


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


##+######################################################################
## Set a MIN-SIZE of the window (roughly).
##
## For WIDTH, allow for a min-width via the  '.fRleft' frame and
## '.fRright.fRbuttons' frame.
##
## For HEIGHT, allow for the INITIAL stacked (unhidden) frames:
##      1 char   high for the '.fRright.fRbuttons'   frame
##      4 chars  high for the '.fRright.fRmsg'       frame
##      1 char   high for the '.fRright.fRinfile'    frame
##      1 char   high for the '.fRright.fRoutHead'   frame
##      1 char   high for the '.fRright.fRcontainer' frame
##      1 char   high for the '.fRright.fRoutfile'   frame
##      1 char   high for the '.fRright.fRplayer'    frame
##      1 char   high for the '.fRright.fRoptsHead'  frame
##      1 char   high for the '.fRright.fRexecOpts'  frame
##+#####################################################################

## FOR WIDTH: (allow for the listbox in the '.fRleft' frame and the
## button widgets in the '.fRright.fRbuttons' frame)

set minWidthPx [font measure fontTEMP_varwidth \
   " $aRtext(buttonEXIT) $aRtext(buttonHELP) $aRtext(buttonEXEC)  \
$aRtext(buttonPLAYOUT) $aRtext(buttonPLAYIN) $aRtext(chkbuttMOREoutparms)"]

## 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}]

## Also add pixels for the listbox --- along with about 10 pixels
## for its vertical scrollbar.

set charWidthPx [font measure fontTEMP_varwidth "W"]

set minWinWidthPx \
   [expr {10 + ($initListboxWidthChars * $charWidthPx) + $minWidthPx}]

##+#################################################
## For HEIGHT --- for
##      1 char   high for the '.fRright.fRbuttons'   frame
##      4 chars  high for the '.fRright.fRmsg'       frame
##      1 char   high for the '.fRright.fRinfile'    frame
##      1 char   high for the '.fRright.fRoutHead'   frame
##      1 char   high for the '.fRright.fRcontainer' frame
##      1 char   high for the '.fRright.fRoutfile'   frame
##      1 char   high for the '.fRright.fRplayer'    frame
##      1 char   high for the '.fRright.fRoptsHead'  frame
##      1 char   high for the '.fRright.fRexecOpts'  frame
##    --------
##     12 chars  high for the 9 frames
##+#################################################

set charHeightPx [font metrics fontTEMP_varwidth -linespace]

set minWinHeightPx [expr {12 * $charHeightPx}]

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

set minWinHeightPx [expr {56 + $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

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

##+####################################################################
##+####################################################################
## DEFINE *ALL* THE FRAMES:
##
##   Top-level :
##   '.fRleft'   to hold a listbox widget with xy scrollbars
##   '.fRright'  to hold the following sub-frames:
##
##   '.fRright.fRbuttons'     for Exit, Help, Exec, Play buttons, one chkbutton.
##   '.fRright.fRmsg'         for a label widget (for messages).
##   '.fRright.fRinfile'      for label-entry-button widgets.
##   '.fRright.fRoutHead'     for a label widget (for a heading).
##   '.fRright.fRcontainer'   for a label and several radiobutton widgets.
##   '.fRright.fRoutfile'     for label-entry widgets.
##   '.fRright.fRplayer'      for label-entry-label widgets.
##   '.fRright.fRoptsHead'    for a label widget (for a heading).
##   '.fRright.fRexecOpts'    for an initial frame with a label widget. This frame
##                            will be replaced by a frame and 1 or more sub-frames
##                            and widgets in the 'show_*_opts' procs.
##   '.fRright.fRvidaud'      for the following sub-frames:
##               (But do not pack '.fRright.fRvidaud'. That will be done if
##                the user clicks the 'MoreMovieOutParms' checkbutton.)
##
##   '.fRright.fRvidaud.fRvideoHead'   for a label widget (for a heading).
##   '.fRright.fRvidaud.fRvidsize'     for label-entry-label widgets.
##   '.fRright.fRvidaud.fRvrate'       for label-entry-label widgets.
##   '.fRright.fRvidaud.fRvcodec'      for label-entry-label widgets.
##   '.fRright.fRvidaud.fRvother'      for label-entry widgets.
##   '.fRright.fRvidaud.fRaudioHead'   for a label widget (for a heading).
##   '.fRright.fRvidaud.fRachannels'   for label-entry-label widgets.
##   '.fRright.fRvidaud.fRacodec'      for label-entry-label widgets.
##   '.fRright.fRvidaud.fRaother'      for label-entry widgets.
##   '.fRright.fRvidaud.fRotherHead'   for a label widget (for a heading).
##   '.fRright.fRvidaud.fRthreads'     for label-entry-label widgets.
##   '.fRright.fRvidaud.fRguide'       for a label widget (for usage info).
##+####################################################################
##+####################################################################

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 .fRleft    -relief $RELIEF_frame  -bd $BDwidth_frame
frame .fRright   -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRleft.fRlistbox    -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRbuttons   -relief $RELIEF_frame  -bd $BDwidth_frame

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

frame .fRright.fRinfile    -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRoutHead   -relief raised  -borderwidth 2

frame .fRright.fRcontainer -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRoutfile   -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRplayer    -relief $RELIEF_frame  -bd $BDwidth_frame


frame .fRright.fRoptsHead   -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRexecOpts  -relief $RELIEF_frame  -bd $BDwidth_frame

## This 'execOpts' frame will be replaced by a frame (containing
## sub-frames and widgets) --- such as 'fRright.fRparametersCLIP'.
## The new frame, sub-frames, and widgets will be defined and packed
## in 'show_*_opts' procs like 'show_CLIP_opts' and 'show_CROP_opts'.
## A 'pack forget' command will be used, in these procs, to replace
## the previously existing frame in this position.

frame .fRright.fRvidaud    -relief $RELIEF_frame  -bd $BDwidth_frame

## We go ahead and define the sub-frames of frame '.fRright.fRvidaud',
## even though they are initially hidden, because the user is quite
## likely to click on the 'MoreMovieOutParms' checkbutton. (The GUI
## comes up quickly in spite of the little bit of processing that
## creates these frames that are initially hidden).

frame .fRright.fRvidaud.fRvideoHead -relief raised         -bd 2

frame .fRright.fRvidaud.fRvsize     -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRvidaud.fRvrate     -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRvidaud.fRvcodec    -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRvidaud.fRvother    -relief $RELIEF_frame  -bd $BDwidth_frame


frame .fRright.fRvidaud.fRaudioHead   -relief raised         -bd 2

frame .fRright.fRvidaud.fRachannels   -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRvidaud.fRacodec      -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRvidaud.fRaother      -relief $RELIEF_frame  -bd $BDwidth_frame


frame .fRright.fRvidaud.fRotherHead   -relief raised         -bd 2

frame .fRright.fRvidaud.fRthreads     -relief $RELIEF_frame  -bd $BDwidth_frame

frame .fRright.fRvidaud.fRguide       -relief raised         -bd 2


##+########################################################
## PACK (almost) *ALL* the FRAMES.
##+########################################################

## Top-level:

pack .fRleft \
   -side left \
   -anchor nw \
   -fill both \
   -expand 1

pack .fRright \
   -side left \
   -anchor nw \
   -fill both \
   -expand 1


## Sub-frames of '.fRleft':
## (In case we want to put another widget or frame in the
##  '.fRleft' frame, we provide a frame for the listbox
##  and its scrollbars.)

pack .fRleft.fRlistbox \
   -side top \
   -anchor nw \
   -fill y \
   -expand 1


## Sub-frames of '.fRright':

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

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

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

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

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

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

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

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

## We pack the frame '.fRright.fRexecOpts'. As was noted above,
## this frame will be replaced by frames (containing sub-frames and
## widgets). The new frames and their sub-frames and widgets will be
## defined and packed by 'show_*_opts' procs like 'show_CLIP_opts'
## and 'show_CROP_opts'.

pack .fRright.fRexecOpts \
   -side top \
   -anchor nw \
   -fill both \
   -expand 1

##+#############################################################
## We do not pack the '.fRright.fRvidaud' frame here.
## We pack (and 'pack forget') the '.fRright.fRvidaud' frame
## (which was defined above) in the proc 'pack_more_outparms_frame'
## which is in the PROCS section below.
## That proc can be used to show/hide the 'more-out-parms' frames,
## via a checkbutton on the GUI.
##+#############################################################
## But we go ahead and pack all the sub-frames of
## the '.fRright.fRvidaud' frame here.
##+#############################################################

pack .fRright.fRvidaud.fRvideoHead \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

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

pack .fRright.fRvidaud.fRvrate \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

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

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

pack .fRright.fRvidaud.fRaudioHead \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRright.fRvidaud.fRachannels \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

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

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

pack .fRright.fRvidaud.fRotherHead \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

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

pack .fRright.fRvidaud.fRguide \
   -side top \
   -anchor nw \
   -fill x \
   -expand 1


## OK. All frames are DEFINED (except for frames that will replace
## '.fRright.fRexecOpts', and sub-frames of those frames) --- and
## all these frames are PACKED (except the '.fRright.fRvidaud' frame
## and the frames that will replace '.fRright.fRexecOpts').
##
## Now define-and-pack the widgets --- except for widgets in
## frames that will replace '.fRright.fRexecOpts'. Those widgets
## will be defined-and-packed in 'show_*_opts' procs.


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


##+######################################################
## In FRAME '.fRleft.fRlistbox' -
## DEFINE-and-PACK a LISTBOX WIDGET,
## with scrollbars --- for a list of 'ffmpeg' ExecOptions.
##+######################################################

listbox .fRleft.fRlistbox.listbox \
   -width $initListboxWidthChars \
   -height $initListboxHeightChars \
   -font fontTEMP_fixedwidth \
   -relief raised \
   -borderwidth $BDwidthPx_listbox \
   -state normal \
   -yscrollcommand ".fRleft.fRlistbox.scrbary set" \
   -xscrollcommand ".fRleft.fRlistbox.scrbarx set"

scrollbar .fRleft.fRlistbox.scrbary \
   -orient vertical \
   -command ".fRleft.fRlistbox.listbox yview"

scrollbar .fRleft.fRlistbox.scrbarx \
   -orient horizontal \
   -command ".fRleft.fRlistbox.listbox xview"


##+##########################################################################
## INSERT 'ffmpeg' 'ExecOption' LISTBOX ENTRIES that hold brief,
## unique movie-file operation identifiers ---
## followed by a separator character (#) --- followed by an
## arbitrary amount of descriptive info.
##
## By adding a '#' at the beginning of each line, we signal
## that that operation is not implemented yet --- but it
## is being considered for addition at some future date.
##+##########################################################################
## FOR EACH OPERATION OPTION ADDED, ADD 2 PROCS TO THE PROCS SECTION.
##
## Note that for each listbox-line added here, there should be
## a couple of procs added to the PROCS section below:
##     'show_*_opts' --- to provide subframe and widget definitions-and-packing.
##                       Example name: 'show_CLIP_opts'
##     'set_*_cmd' --- to execute 'ffmpeg' with appropriate parameters.
##                     Example name: 'set_CLIP_cmd'
##
## In the proc 'show_*_opts', there should be
## frame and widget definitions and pack statements for
## the new frame and new widgets.
##
## See the 'show_CLIP_opts' and 'show_CROP_opts' procs for examples of how
## the previous parameters-frame is REMOVED by a 'pack forget' command,
## and THEN the CLIP or CROP frame is packed.
##+##########################################################################

## Make sure the listbox is empty.

.fRleft.fRlistbox.listbox delete 0 end

## New OPERATION OPTIONS are to be added/activated here:
## (Also add corresponding 'show_*_opts' & 'set_*_cmd' procs in the PROCS section below.)

.fRleft.fRlistbox.listbox insert end "CLIP # For a given start-time and duration-time, makes a movie 'clip' from the input movie file."
.fRleft.fRlistbox.listbox insert end "CROP # For specified crop side (bottom/top/left/right) and crop-pixels, makes a movie with 'cropped' image size."
.fRleft.fRlistbox.listbox insert end "PROPERTIES-IN # Shows properties of the INPUT movie file, using 'ffmpeg -i'"
.fRleft.fRlistbox.listbox insert end "PROPERTIES-OUT # Shows properties of the OUTPUT movie file, using 'ffmpeg -i'."
.fRleft.fRlistbox.listbox insert end "CONVERT # Converts the input movie file to a new movie file with specified container-video-audio format parameters."

.fRleft.fRlistbox.listbox insert end "## NOT IMPLEMENTED YET:"
.fRleft.fRlistbox.listbox insert end "# CHG-VOLUME # Makes a new movie file with changed audio volume."
.fRleft.fRlistbox.listbox insert end "# EXTRACT-AUDIO # Gets the audio stream(s) from a movie and puts them in an audio file, such as 'mp3' or 'wav'."
.fRleft.fRlistbox.listbox insert end "# REMOVE-AUDIO # Removes audio stream(s) to make a soundless movie file."
.fRleft.fRlistbox.listbox insert end "# ADD-AUDIO # Adds audio stream(s) to a movie to make a new movie file."
.fRleft.fRlistbox.listbox insert end "# TIME-LAPSE # Makes a 'time-lapse' movie from a given movie. You specify SECONDS between frames --- OR NUMBER of frames and start-time and duration."
.fRleft.fRlistbox.listbox insert end "# FLIP # Makes a new movie by flipping the video of the input movie, horizontally or vertically."
.fRleft.fRlistbox.listbox insert end "# EXTRACT-IMAGES # Extracts one or more images from a given movie --- into JPEG files or some other format."


##+##############################################################
## Get the number of exec-operations loaded into the listbox ---
## to show users how many are in the listbox, including those that
## may be out of sight. This number may be displayed on the right
## of the '.fRbuttons' frame, for example.
##+##############################################################

set numExecOps [.fRleft.fRlistbox.listbox index end]


##+####################################
## Pack the listbox and its scrollbars.
##+####################################

pack .fRleft.fRlistbox.scrbary \
   -side right \
   -anchor e \
   -fill y \
   -expand 0

pack .fRleft.fRlistbox.scrbarx \
   -side bottom \
   -anchor s \
   -fill x \
   -expand 0

## We need to pack the listbox AFTER
## the scrollbars, to get the scrollbars
## positioned properly --- BEFORE
## the listbox FILLS the pack area.

pack .fRleft.fRlistbox.listbox \
   -side top \
   -anchor nw \
   -fill both \
   -expand 1


##+##################################################################
## IN THE '.fRright.fRbuttons' frame -- DEFINE several BUTTON widgets
## --- Exit, Help, ExecOption, PlayOutMovie, PlayInMovie.
## Also DEFINE a CHECKBUTTON widget. Then PACK THE WIDGETS.
##+##################################################################

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

button .fRright.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 .fRright.fRbuttons.buttEXEC \
   -text "$aRtext(buttonEXEC)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {exec_movie_operation}


button .fRright.fRbuttons.buttPLAYOUT \
   -text "$aRtext(buttonPLAYOUT)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {play_movie_out}

button .fRright.fRbuttons.buttPLAYIN \
   -text "$aRtext(buttonPLAYIN)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {play_movie_in}

## DEFINE Checkbutton for Show/Hide-MoreOutParms.

set SHOWoutparms0or1 0

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


##+###################################################
## Pack the widgets in the '.fRright.fRbuttons' frame.
##+###################################################
## You can easily change the order of the buttons by
## re-arranging the order of these widgets in the pack
## statement. For example, you could move 'buttPLAYOUT'
## above 'buttPLAYIN', to move the 'PlayOutMovie' button
## to the left of the 'PlayInMovie' button on the GUI.
##+####################################################

pack .fRright.fRbuttons.buttEXIT \
     .fRright.fRbuttons.buttHELP \
     .fRright.fRbuttons.buttEXEC \
     .fRright.fRbuttons.buttPLAYIN \
     .fRright.fRbuttons.buttPLAYOUT \
     .fRright.fRbuttons.chkbuttMOREoutparms \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


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

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

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


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

label .fRright.fRinfile.labelINFILE \
   -text "$aRtext(labelINFILE)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

entry .fRright.fRinfile.entryINFILE \
   -textvariable INfilename \
   -bg $entryBKGD \
   -font fontTEMP_fixedwidth \
   -relief sunken \
   -bd $BDwidthPx_entry

button .fRright.fRinfile.buttBROWSE \
   -text "$aRtext(buttBROWSE)" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {get_INfilename}

## PACK the widgets in the '.fRright.fRinfile' frame.

pack .fRright.fRinfile.labelINFILE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0

pack .fRright.fRinfile.entryINFILE \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

pack .fRright.fRinfile.buttBROWSE \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


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

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

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


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

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

## DEFINE Radiobuttons for container formats :
## (To set the value of the variable for each radiobutton, we use
##  the exact string that 'ffmpeg' uses to specify the container format.)

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

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

# .fRright.fRcontainer.radbuttMPEG4 configure -state disabled

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

# .fRright.fRcontainer.radbuttMPEG configure -state disabled

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

# .fRright.fRcontainer.radbuttFLV configure -state disabled

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

# .fRright.fRcontainer.radbuttAVI configure -state disabled

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

.fRright.fRcontainer.radbuttWEBM configure -state disabled

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

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


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

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

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

## COMMENTED OUT this 'Browse' button, for now.
if {0} {
button .fRright.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 '.fRright.fRoutfile' frame.

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

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

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

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

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

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

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

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

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

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

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


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

label .fRright.fRoptsHead.labelOPTShead \
   -text "$aRtext(labelOPTShead)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label \
   -bg $headBKGD

pack .fRright.fRoptsHead.labelOPTShead \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

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

label .fRright.fRexecOpts.labelEXECopts \
   -text "$aRtext(labelEXECopts)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

pack .fRright.fRexecOpts.labelEXECopts \
   -side left \
   -anchor w \
   -fill x \
   -expand 1

## Set a variable that we will use to replace this frame
## with other 'execOpts' frames, using 'pack forget' in
## the 'set_*_opts' procs.

set curEXECOPTSframe ".fRright.fRexecOpts"


##+############################################################
## IN THE '.fRright.fRvidaud.fRvideoHead' frame -- DEFINE one
## LABEL widget.  Then PACK IT.
##+############################################################

label .fRright.fRvidaud.fRvideoHead.labelVIDEOHEAD \
   -text "$aRtext(labelVIDEOHEAD)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label \
   -bg $headBKGD

pack .fRright.fRvidaud.fRvideoHead.labelVIDEOHEAD \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


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

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

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

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

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

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


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

label .fRright.fRvidaud.fRvrate.labelVRATE1 \
   -text "$aRtext(labelVRATE1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

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

label .fRright.fRvidaud.fRvrate.labelVRATE2 \
   -text "$aRtext(labelVRATE2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label


## PACK the widgets in the '.fRright.fRvidaud.fRvrate' frame.

pack  .fRright.fRvidaud.fRvrate.labelVRATE2 \
      .fRright.fRvidaud.fRvrate.entryVRATE \
      .fRright.fRvidaud.fRvrate.labelVRATE1 \
   -side right \
   -anchor e \
   -fill none \
   -expand 0


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

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

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

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


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

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



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

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

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

#   -width 10 \

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

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

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


##+############################################################
## IN THE '.fRright.fRvidaud.fRaudioHead' frame -- DEFINE one
## LABEL widget.  Then PACK IT.
##+############################################################

label .fRright.fRvidaud.fRaudioHead.labelAUDIOHEAD \
   -text "$aRtext(labelAUDIOHEAD)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label \
   -bg $headBKGD

## PACK the widgets in the '.fRright.fRvidaud.fRaudioHead' frame.

pack  .fRright.fRvidaud.fRaudioHead.labelAUDIOHEAD \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


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

label .fRright.fRvidaud.fRachannels.labelACHANNELS1 \
   -text "$aRtext(labelACHANNELS1)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label

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

label .fRright.fRvidaud.fRachannels.labelACHANNELS2 \
   -text "$aRtext(labelACHANNELS2)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label


## PACK the widgets in the '.fRright.fRvidaud.fRachannels' frame:

pack .fRright.fRvidaud.fRachannels.labelACHANNELS2 \
     .fRright.fRvidaud.fRachannels.entryACHANNELS \
     .fRright.fRvidaud.fRachannels.labelACHANNELS1 \
   -side right \
   -anchor e \
   -fill none \
   -expand 0


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

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

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

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

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

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


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

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

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

#   -width 30 \

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

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

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


##+############################################################
## IN THE '.fRright.fRvidaud.fRotherHead' frame -- DEFINE one
## LABEL widget.  Then PACK IT.
##+############################################################

label .fRright.fRvidaud.fRotherHead.labelOTHERHEAD \
   -text "$aRtext(labelOTHERHEAD)" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief $RELIEF_label_lo \
   -bd $BDwidthPx_label \
   -bg $headBKGD

pack .fRright.fRvidaud.fRotherHead.labelOTHERHEAD \
   -side left \
   -anchor w \
   -fill x \
   -expand 1


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

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

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

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

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

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

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

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


##+########################################################
## IN THE '.fRright.fRvidaud.fRguide' frame -- DEFINE one
## LABEL widget.  Then PACK IT.
##+########################################################

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

## PACK the widgets in the '.fRright.fRvidaud.fRguide' frame:

pack .fRright.fRvidaud.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.
##                   Also bindings on the checkbutton and the listbox.
##+#####################################################################

## Bindings for the 'Container' radiobuttons.

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

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

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

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

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

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


## Bindings for the 'MoreMovieOutParms' checkbutton.

bind .fRright.fRbuttons.chkbuttMOREoutparms  <ButtonRelease-1>  \
   {pack_more_outparms_frame}


## Bindings for the listbox widget.

bind .fRleft.fRlistbox.listbox <ButtonRelease-1>  {loadOptsFrame_perListboxSelection}


##+##########################################################################
##+##########################################################################
## DEFINE PROCEDURES:
##
##  'get_INfilename'               - called by the movie in-file 'Browse' button.
##
##  'get_chars_before_last'        - called by the proc 'get_INfilename'.
##
##  'set_defaults_for_container'   - called by bindings on the CONTAINER
##                                   radiobuttons.
##
##                                   Sets defaults for the video-audio-other
##                                   GUI widgets, for a given container type.
##
##  'loadOptsFrame_perListboxSelection' - called by a click on the listbox.
##
##                                 Calls on a 'show_*_opts' proc depending on
##                                 the listbox line (movie-exec-operation) selected.
##
##                                 Example proc name: 'show_CLIP_opts'
##
##  'exec_movie_operation'       - called by a click on the 'ExecOption' button.
##
##                                 Calls on a 'set_*_cmd' proc depending on
##                                 the listbox line (media-file-operation) selected.
##
##                                 Example proc name: 'set_CLIP_cmd'
##
##                                 Then executes the 'ffmpeg' command string built by
##                                 the 'set_*_cmd' proc --- in an 'xterm' window.
##
##--------------------------------------------------------------------------------------
## For each ExecOption added to the listbox, a 'show_*_opts' proc and a 'set_*_cmd' proc
## should be provided --- like the following.
##           (And calls will need to be added to the 2 procs above:
##            'loadOptsFrame_perListboxSelection' and 'exec_movie_operation'.)
##--------------------------------------------------------------------------------------
##  'show_CLIP_opts'            - called by a button1-release binding on the listbox,
##                                which calls the 'loadOptsFrame_perListboxSelection' proc.
##
##                                Loads 'clip' frames and widgets into an 'execOpts' frame.
##
##  'set_CLIP_cmd'              - called by the 'exec_movie_operation' proc which is called
##                                by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string for CLIPPING --- to be
##                                used in the proc 'exec_movie_operation'.
##
##--------------------------------------------------------------------------------------
##  'show_CROP_opts'            - called by a button1-release binding on the listbox,
##                                which calls the 'loadOptsFrame_perListboxSelection' proc.
##
##                                Loads 'crop' frames and widgets into an 'execOpts' frame.
##
##  'set_CROP_cmd'              - called by the 'exec_movie_operation' proc which is called
##                                by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string for CROPPING --- to be
##                                used in the proc 'exec_movie_operation'.
##
##--------------------------------------------------------------------------------------
##  'show_PROPSin_opts'         - called by a button1-release binding on the listbox,
##                                which calls the 'loadOptsFrame_perListboxSelection' proc.
##
##                                Loads 'PROPSin' frames and widgets into an 'execOpts' frame.
##
##  'set_PROPSin_cmd'           - called by the 'exec_movie_operation' proc which is called
##                                by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string for showing properties
##                                of the input media file. The command string is to be used
##                                in the proc 'exec_movie_operation'.
##
##--------------------------------------------------------------------------------------
##  'show_PROPSout_opts'        - called by a button1-release binding on the listbox,
##                                which calls the 'loadOptsFrame_perListboxSelection' proc.
##
##                                Loads 'PROPSout' frames and widgets into an 'execOpts' frame.
##
##  'set_PROPSout_cmd'          - called by the 'exec_movie_operation' proc which is called
##                                by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string for showing properties
##                                of the output media file. The command string is to be used
##                                in the proc 'exec_movie_operation'.
##
##--------------------------------------------------------------------------------------
##  'show_CONVERT_opts'         - called by a button1-release binding on the listbox,
##                                which calls the 'loadOptsFrame_perListboxSelection' proc.
##
##                                Loads 'crop' frames and widgets into an 'execOpts' frame.
##
##  'set_CONVERT_cmd'           - called by the 'exec_movie_operation' proc which is called
##                                by the 'ExecOption' button.
##
##                                Sets an 'ffmpeg' command string for CONVERTING the input
##                                media file to a new container and/or video and/or audio
##                                format. The command string is to be used in the proc
##                                'exec_movie_operation'.
##
##--------------------------------------------------------------------------------------
##
##  'play_movie_out'           - called by the 'PlayOutMovie' button. Launches a movie
##                               'player' program on the output movie file.
##
##  'play_movie_in'            - called by the 'PlayInMovie' button. Launches a movie
##                               'player' program on the input movie file.
##
##  'set_width_of_labels'      - called in the 'Additional GUI Initialization'
##                               section at the bottom of this script.
##
##                               Sets 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.
##
##  'pack_more_outparms_frame'  - called by button1-release binding on the
##                                'MoreMovieOutParms' checkbutton.
##
##                                Shows the 'video', 'audio', and 'other' frames
##                                of the GUI if the 'MoreMovieOutParms' checkbutton
##                                is ON. OR, 'forgets' the frame containing
##                                the 'video', 'audio', and 'other' frames.
##
##  'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
##+#####################################################################
##+#####################################################################

##+#####################################################################
## PROC 'get_INfilename'
##+#####################################################################
## PURPOSE: To get a filename to use for the input movie file.
##          Put the filename in the entry field variable, INfilename.
##
## CALLED BY: the 'Browse ...' button in frame '.fRinfile'.
##+#####################################################################

proc get_INfilename {} {

   ## INPUT globals:
   global inDIR
   # global env

   ## INPUT-OUTPUT globals:
   global INfilename

   ## Get a file name.

   set fName [tk_getOpenFile -parent . \
      -title "Select the filename of the input movie file." \
      -initialdir "$inDIR" ]

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

   ## Check if fName var is empty.

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

   ## Put $fName in INfilename. Reset the inDIR var.

   if {[file exists "$fName"]} {
      set INfilename "$fName"
      .fRright.fRinfile.entryINFILE xview end
      set inDIR [ get_chars_before_last / in "$INfilename" ]
   }

}
## END OF PROC 'get_INfilename'


##+###################################################################
## 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.
##
## NOTE: We set the default 'player' here, according to the 'container'
##       chosen for the output file, just in case there are cases
##       where a certain 'player' is more successful with certain
##       'container' formats.
##
## NOTE2: I have encountered movies that would NOT play with
##         'vlc' or 'totem', but they WOULD play with 'ffplay'
##         and 'mplayer' and 'gmplayer'.
##
## 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 OUTfilename ENTRYplayer \
      VIDEOsize  VIDEOrate \
      VIDEOcodec VIDEOotherParms AUDIOchannels \
      AUDIOcodec AUDIOotherParms Nthreads

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

   if {"$container" == "matroska"} {
      set OUTfilename "$outDIR/$env(USER)_output_movie.mkv"
      set ENTRYplayer "ffplay"
      set VIDEOsize "800x600"
      set VIDEOrate "25"
      set VIDEOcodec "libx264"
      set VIDEOotherParms "-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset -crf 22"
      set AUDIOchannels "1"
      set AUDIOcodec "pcm_s16le"
      set AUDIOotherParms "-ar 22050 -ab 96k"
      set Nthreads "1"
   }
   ## END OF   if {"$container" == "matroska"}


   #########################
   ## FOR 'mp4' CONTAINER:
   #########################

   if {"$container" == "mp4"} {
      set OUTfilename "$outDIR/$env(USER)_output_movie.mp4"
      set ENTRYplayer "ffplay"
      set VIDEOsize "800x600"
      set VIDEOrate "25"
      set VIDEOcodec "libx264"
      set VIDEOotherParms "-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset -crf 22"
      set AUDIOchannels "1"
      set AUDIOcodec "libmp3lame"
      set AUDIOotherParms "-ar 44100 -ab 128k"
      set Nthreads "1"
   }
   ## END OF   if {"$container" == "mp4"}


   #########################
   ## FOR 'mpeg' CONTAINER:
   #########################

   if {"$container" == "mpeg"} {
      set OUTfilename "$outDIR/$env(USER)_output_movie.mpg"
      set ENTRYplayer "ffplay"
      set VIDEOsize "800x600"
      set VIDEOrate "25"
      set VIDEOcodec "mpeg2video"
      set VIDEOotherParms "-bufsize 1835k"
      set AUDIOchannels "1"
      set AUDIOcodec "libmp3lame"
      set AUDIOotherParms "-ar 44100 -ab 128k"
      set Nthreads "1"
   }
   ## END OF   if {"$container" == "mpeg"}


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

   if {"$container" == "flv"} {
      set OUTfilename "$outDIR/$env(USER)_output_movie.flv"
      set ENTRYplayer "ffplay"
      set VIDEOsize "800x600"
      set VIDEOrate "25"
      set VIDEOcodec "libx264"
      set VIDEOotherParms "-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset -crf 22""
      set AUDIOchannels "1"
      set AUDIOcodec "libfaac"
      set AUDIOotherParms "-ar 44100 -ab 128k"
      set Nthreads "1"
   }
   ## END OF   if {"$container" == "flv"}


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

   if {"$container" == "avi"} {
      set OUTfilename "$outDIR/$env(USER)_output_movie.avi"
      set ENTRYplayer "ffplay"
      set VIDEOsize "800x600"
      set VIDEOrate "25"
      set VIDEOcodec "mpeg4"
      set VIDEOotherParms ""
      set AUDIOchannels "1"
      set AUDIOcodec "libmp3lame"
      set AUDIOotherParms "-ar 44100 -ab 128k"
      set Nthreads "1"
   }
   ## END OF   if {"$container" == "avi"}


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

   if {"$container" == "webm"} {
      ##
      ## REQUIRES TWO-PASSES WITH 'ffmpeg'??
      ##
      set OUTfilename "$outDIR/$env(USER)_output_movie.webm"
      set ENTRYplayer "ffplay"
      set VIDEOsize "800x600"
      set VIDEOrate "25"
      set VIDEOcodec "libvpx"
      set VIDEOotherParms ""
      set AUDIOchannels "1"
      set AUDIOcodec "vorbis"
      set AUDIOotherParms "-ar 44100 -ab 128k"
      set Nthreads "1"

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

}
## END OF PROC 'set_defaults_for_container'


##+#########################################################################
## proc  'loadOptsFrame_perListboxSelection'
##+#########################################################################
## PURPOSE: Calls on a 'show_*_opts' proc
##          depending on the exec-options listbox line selected.
##
## CALLED BY: button1-release on the listbox.
##
## See the listbox insert statements above (where the listbox widget was
## defined) for the exec-option ID strings that were loaded in the listbox.
##+#########################################################################

proc loadOptsFrame_perListboxSelection {} {

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

   ## OUTPUT globals:
   global VARexecOption

   set sel_INDEX [ .fRleft.fRlistbox.listbox curselection ]

   if { $sel_INDEX != "" } {
      set EXECline  [ .fRleft.fRlistbox.listbox get $sel_INDEX ]

      ## Extract the first part of the selected listbox line (before the
      ## first '#' character) into the variable 'VARexecOption'.

      set TEMPlist [split $EXECline #]
      set VARexecOption [lindex $TEMPlist 0]
      set VARexecOption [string trim $VARexecOption]
   } else {return}


   ## FOR TESTING:
   #   puts "proc 'loadOptsFrame_perListboxSelection' >  VARexecOption: $VARexecOption"

   if {"$VARexecOption" == ""} {return}

   #####################################################################################
   ## For the just-selected ExecOption, run the corresponding 'show_*_opts' proc.
   #####################################################################################

   if {"$VARexecOption" == "CLIP"} {show_CLIP_opts}

   if {"$VARexecOption" == "CROP"} {show_CROP_opts}

   if {"$VARexecOption" == "PROPERTIES-IN"} {show_PROPSin_opts}

   if {"$VARexecOption" == "PROPERTIES-OUT"} {show_PROPSout_opts}

   if {"$VARexecOption" == "CONVERT"} {show_CONVERT_opts}

   ####################################################################################
   ## THE FOLLOWING EXEC-OPTIONS ARE ON MY 'TO-IMPLEMENT' LIST.
   ####################################################################################

   # if {"$VARexecOption" == "CHG-VOLUME"} {show_CHG-VOLUME_opts}

   # if {"$VARexecOption" == "EXTRACT-AUDIO"} {show_EXTRACT-AUDIO_opts}

   # if {"$VARexecOption" == "REMOVE-AUDIO"} {show_REMOVE-AUDIO_opts}

   # if {"$VARexecOption" == "ADD-AUDIO"} {show_ADD-AUDIO_opts}

   # if {"$VARexecOption" == "TIME-LAPSE"} {show_TIME-LAPSE_opts}

   # if {"$VARexecOption" == "FLIP"} {show_FLIP_opts}

   # if {"$VARexecOption" == "EXTRACT-IMAGES"} {show_EXTRACT-IMAGES_opts}

}
## END OF PROC 'loadOptsFrame_perListboxSelection'


##+#####################################################################
## PROC 'exec_movie_operation'
##+#####################################################################
## PURPOSE: To call on the appropriate 'set_*_cmd' proc and then
##          use the 'ffmpeg' command string in the variable 'ffmpegCMD'
##          to execute 'ffmpeg' --- in an 'xterm' window.
##
## CALLED BY:  a click on the 'ExecOption' button.
##+#####################################################################

proc exec_movie_operation { } {

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

   ## INPUT globals:
   global VARexecOption INfilename OUTfilename ffmpegCMD DIRscripts

   ## The other parameters for making the movie file are used
   ## in the 'set_*_cmd' procs called below. Those parameters include
   ##   VIDEOsize VIDEOrate VIDEOcodec VIDEOotherParms
   ##   AUDIOchannels AUDIOcodec AUDIOotherParms
   ##   Nthreads CONTAINERformat
   ## We do not need to declare them as global here. They are
   ## incorporated in the 'ffmpegCMD' global variable.

   ## If we ever need to, we could add a 'DELAYseconds' prompt on the GUI,
   ## and insert a pause here to delay the start of the 'ffmpeg' processing.

   # set DELAYmillisecs [expr {$DELAYseconds * 1000}]
   # after $DELAYmillisecs

   ################################################################
   ## If the no option has been selected yet, simply return.
   ## (We could popup a message here to advise the use to select
   ##  an option from the listbox.)
   ################################################################

   if {"$VARexecOption" == ""} {return}

   ## FOR TESTING:
   #   puts "proc 'exec_movie_operation': VARexecOption: $VARexecOption"

   ################################################################
   ## Advise the user that processing is starting? Not needed?
   ################################################################

   # .fRright.fRmsg.labelMSG configure -text "Processing is starting for the chosen ExecOption."
   # update idletasks


   ##############################################################
   ## Remove trailing and leading blanks (if any) from the user's
   ## entry in the input and output filename 'entry' widgets.
   ##############################################################

   set INfilename  [string trim "$INfilename"]
   set OUTfilename [string trim "$OUTfilename"]


   ###################################################################
   ## If 'VARexecOption' is 'PROPERTIES-IN' or 'PROPERTIES-OUT', we
   ## do NOT fall into the 'MAKE OUTPUT FILE' section below. We
   ## simply put the output of the 'ffmpeg -i' command in a variable
   ## and show it in a popup window and return out of this proc.
   ###################################################################


   ##############################################################
   ## Do the 'PROPERTIES-IN' processing and return.
   ##############################################################

   if {"$VARexecOption" == "PROPERTIES-IN"} {

      if {![file exists "$INfilename"]} {
         popup_msgVarWithScroll .topINFILE \
            "The file named in the INPUT-movie-file field was not found."
         return
      }

      #######################################################
      ## See the comments on 'foreground' and 'background'
      ## execution with the Tcl 'exec' command, in the
      ## 'MAKE OUTPUT FILE' section below.
      ## I try using the 'foreground' method first.
      ## I may switch this to a 'background' method later.
      ######################################################

      set PROPStext [exec $DIRscripts/movieFilePROPERTIES_ffmpeg-i.sh "$INfilename"]

      popup_msgVarWithScroll .topPROPSin "$PROPStext"

      return
   }
   ## END OF if


   ##############################################################
   ## Do the 'PROPERTIES-OUT' processing and return.
   ##############################################################

   if {"$VARexecOption" == "PROPERTIES-OUT"} {

      if {![file exists "$INfilename"]} {
         popup_msgVarWithScroll .topOUTFILE \
            "The file named in the OUTPUT-movie-file field was not found."
         return
      }

      #######################################################
      ## See the comments on 'foreground' and 'background'
      ## execution with the Tcl 'exec' command, in the
      ## 'MAKE OUTPUT FILE' section below.
      ## I try using the 'foreground' method first.
      ## I may switch this to a 'background' method later.
      ######################################################

      set PROPStext [exec $DIRscripts/movieFilePROPERTIES_ffmpeg-i.sh "$OUTfilename"]

      popup_msgVarWithScroll .topPROPSout "$PROPStext"

      return
   }
   ## END OF if


   #####################################################################
   ## If we got here, the user is trying to exec an option other than
   ## PROPERTIES-IN or PROPERTIES-OUT.
   #####################################################################
   ## According to the currently selected option in the listbox,
   ## execute the corresponding 'set_*_cmd' proc --- to set the
   ## 'ffmpegCMD' variable.
   #####################################################################

   if {"$VARexecOption" == "CLIP"} {set_CLIP_cmd}

   if {"$VARexecOption" == "CROP"} {set_CROP_cmd}

   if {"$VARexecOption" == "CONVERT"} {set_CONVERT_cmd}


   ####################################################################
   ## The following exec-options are on my 'TO-IMPLEMENT' list.
   ####################################################################

   # if {"$VARexecOption" == "CHG-VOLUME"} {set_CHG-VOLUME_cmd}

   # if {"$VARexecOption" == "EXTRACT-AUDIO"} {set_EXTRACT-AUDIO_cmd}

   # if {"$VARexecOption" == "REMOVE-AUDIO"} {set_REMOVE-AUDIO_cmd}

   # if {"$VARexecOption" == "ADD-AUDIO"} {set_ADD-AUDIO_cmd}

   # if {"$VARexecOption" == "TIME-LAPSE"} {set_TIME-LAPSE_cmd}

   # if {"$VARexecOption" == "FLIP"} {set_FLIP_cmd}

   # if {"$VARexecOption" == "EXTRACT-IMAGES"} {set_EXTRACT-IMAGES_cmd}

   ## FOR TESTING:
   #   puts "proc 'exec_movie_operation' - ffmpegCMD: $ffmpegCMD"

   ###################################################################
   ## MAKE THE OUTPUT FILE --- by executing the 'ffmpegCMD' string
   ## in an 'xterm' window.
   ####################################################################
   ## SOME SYNTAX NOTES on running a program via the Tcl 'exec' command:
   ####################################################################
   ## 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 '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 "$...."
   ####################################################################


   #########################################################################
   ## Following is a 'background' run per page 107 of
   ## 'Practical Programming in Tcl & Tk'.
   ##
   ## I run 'ffmpeg' in an 'xterm' window so that encoding messages can be
   ## seen by the user. I use the '-hold' option on 'xterm' so that the
   ## window is held open when 'ffmpeg' processing stops --- so that the
   ## user can review the 'ffmpeg' processing messages and error messages,
   ## if any.
   #########################################################################
   ## 'eval' is needed here?? Because??
   ## To avoid an 'unrecognized option' error when
   ## $VIDEOotherParms was appended to the 'ffmpeg' command??
   ###########################################################################
   ## If there are problems with calling 'xterm' and 'ffmpeg' from within this
   ## Tk script (with the many parameters to 'ffmpeg'), we could switch to
   ## using an 'external' shell script to execute the 'xterm' and 'ffmpeg'
   ## commands (with the many options and parameters).
   ###########################################################################

   set RETcode [ catch {exec xterm -title 'ffmpeg' -bg black -fg white -hold \
      -geometry 90x48+100+100 -e $ffmpegCMD &} XtermPID ]

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

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

   ## FOR TESTING:
   if {0} {
       puts ""
       puts "***********************"
       puts "PROC 'exec_movie_operation' ran 'ffmpeg' with"
       puts "OUTfilename: $OUTfilename"
       puts "and got"
       puts "RETcode: $RETcode"
       puts "XtermPID: $XtermPID"
       puts "***********************"
       puts ""
   }

   #############################################################
   ## Restore the message in the MSG frame? A couple of seconds
   ## after the job is submitted? Not needed?
   #############################################################

   # after 2000
   # .fRright.fRmsg.labelMSG configure -text "$aRtext(labelMSG)"

}
## END OF PROC 'exec_movie_operation'


##+#####################################################################
## PROC 'show_CLIP_opts'
##+#####################################################################
## PURPOSE: Loads appropriate 'CLIP' frames and widgets into the
##          '.fRright.fRparametersCLIP' frame.
##
## CALLED BY: proc 'loadOptsFrame_perListboxSelection', which is called
##            by a button1-release binding on the listbox.
##+#####################################################################

proc show_CLIP_opts { } {

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

   ## INPUT globals:
   global  RELIEF_frame  BDwidth_frame  aRtext SHOWoutparms0or1 \
      PADXpx_label  PADYpx_label  RELIEF_label_lo  BDwidthPx_label \
      entryBKGD  BDwidthPx_entry

   ## OUTPUT globals:
   global  curEXECOPTSframe  VARstartTime  VARdurationTime

   ## If the frame for CLIP parameters is not defined yet,
   ## define the CLIP frame. Also define any SUB-frames that might
   ## be needed for lines of widgets. Also define and pack the widgets.

   if {![winfo exists .fRright.fRparametersCLIP]} {

      frame .fRright.fRparametersCLIP   -relief $RELIEF_frame  -bd $BDwidth_frame
      frame .fRright.fRparametersCLIP.fRclip1   -relief $RELIEF_frame  -bd $BDwidth_frame

      ## We go ahead and define a sub-frame, just in case we ever want to add
      ## more clip parameters in another sub-frame.

      ## We pack the one sub-frame here (to do it only once), but we
      ## pack the parent frame below --- doing the parent-forget-and-pack
      ## each time a CLIP operation is requested by the user.

      pack .fRright.fRparametersCLIP.fRclip1 \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      ##+########################################################
      ## In the '.fRright.fRparametersCLIP.fRclip1' frame -
      ## DEFINE 2 ENTRY widgets, for start-time and duration-time
      ## --- along with 2 LABEL widgets.
      ## PACK the 4 label and entry widgets.
      ##+########################################################

      label .fRright.fRparametersCLIP.fRclip1.labelSTARTtime \
         -text "$aRtext(labelSTARTtime)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      ## The entry variables, VARstartTime and VARdurationTime,
      ## could be initialized in the additional-GUI-initialization
      ## section at the bottom of this script --- if you
      ## prefer to initialize them there.

      set VARstartTime "00:00:05"

      entry .fRright.fRparametersCLIP.fRclip1.entrySTARTtime \
         -textvariable VARstartTime \
         -font fontTEMP_fixedwidth \
         -width 9 \
         -bg "$entryBKGD" \
         -relief sunken \
         -bd $BDwidthPx_entry

      label .fRright.fRparametersCLIP.fRclip1.labelDURATIONtime \
         -text "$aRtext(labelDURATIONtime)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      set VARdurationTime "00:14:23"

      entry .fRright.fRparametersCLIP.fRclip1.entryDURATIONtime \
         -textvariable VARdurationTime \
         -font fontTEMP_fixedwidth \
         -width 9 \
         -bg "$entryBKGD" \
         -relief sunken \
         -bd $BDwidthPx_entry

      ## Pack the widgets in frame '.fRright.fRparametersCLIP.fRclip1'.

      pack .fRright.fRparametersCLIP.fRclip1.labelSTARTtime \
           .fRright.fRparametersCLIP.fRclip1.entrySTARTtime \
           .fRright.fRparametersCLIP.fRclip1.labelDURATIONtime \
           .fRright.fRparametersCLIP.fRclip1.entryDURATIONtime \
         -side left \
         -anchor w \
         -fill none \
         -expand 0

   }
   ## END OF if {![winfo exists .fRright.fRparametersCLIP]}

   ## FOR TESTING:
   #  puts "proc 'show_CLIP_opts' > Replacing curEXECOPTSframe: $curEXECOPTSframe"

   ## Remove the current parent 'execOpts' frame (and the frames below it,
   ## if any) and re-pack using the 'fRparametersCLIP' parent frame.

   pack forget $curEXECOPTSframe .fRright.fRvidaud

   set SHOWoutparms0or1 0

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

   set curEXECOPTSframe ".fRright.fRparametersCLIP"

   ## FOR TESTING:
   #  puts "proc 'show_CLIP_opts' > 'pack forget' and re-pack was done."
   #  puts "proc 'show_CLIP_opts' > curEXECOPTSframe IS: $curEXECOPTSframe"

}
## END OF PROC 'show_CLIP_opts'


##+#####################################################################
## PROC 'set_CLIP_cmd'
##+#####################################################################
## PURPOSE: Builds the 'ffmpeg' command for the CLIP operation, using
##          'CLIP' parameters from 'CLIP' frames and widgets in the
##          '.fRright.fRparametersCLIP' frame --- along with
##           container-video-audio parameters from other GUI widgets.
##
##          Puts the command in global variable 'ffmpegCMD'.
##
## CALLED BY:  proc 'exec_movie_operation' which is called by a click on the
##             'ExecOption' button.
##+#####################################################################
## REFERENCE: feNautilusScripts script
## '03a_1movieFile_CLIP-start-length_ffmpeg-ss-t_toMP4-H264-AAC.sh'
##  uses the following ordering of parameters to CLIP a movie file
## --- and write out a movie file in MP4-H264-AAC container-video-audio
## format.
##
##      ffmpeg -i "$FILENAME" \
##            -ss $STARTTIME \
##            -t $DURATION -f mp4 \
##            -copyts -async 1 \
##            -vcodec libx264 \
##            -vpre /usr/share/ffmpeg/libx264-lossless_slow.ffpreset \
##            -crf 22 \
##            -acodec libfaac -ab 128k -ar 22050 -ac 1 \
##            -threads 1 "$FILEOUT"
##+####################################################################

proc set_CLIP_cmd { } {

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

   ## INPUT globals:
   global INfilename OUTfilename \
      VIDEOcodec VIDEOotherParms \
      AUDIOchannels AUDIOcodec AUDIOotherParms \
      Nthreads CONTAINERformat \
      VARstartTime VARdurationTime

   ## If we want to use these parms, we should add 2 checkbuttons
   ## to the CLIP widgets, to allow the user to specify whether
   ## to re-size or re-rate the output as the clip is done.
   #    VIDEOsize VIDEOrate

   ## OUTPUT globals:
   global ffmpegCMD

   set ffmpegCMD "ffmpeg -i \"$INfilename\" \
      -ss $VARstartTime -t $VARdurationTime \
      -f $CONTAINERformat \
      -copyts -async 1 \
      -vcodec $VIDEOcodec $VIDEOotherParms \
      -acodec $AUDIOcodec -ac $AUDIOchannels $AUDIOotherParms \
      -threads $Nthreads \"$OUTfilename\" "

}
## END OF PROC 'set_CLIP_cmd'


##+#####################################################################
## PROC 'show_CROP_opts'
##+#####################################################################
## PURPOSE: Loads appropriate 'CROP' frames and widgets into the
##          '.fRright.fRparametersCROP' frame.
##
## CALLED BY: proc 'loadOptsFrame_perListboxSelection', which is called
##            by a button1-release binding on the listbox.
##+#####################################################################

proc show_CROP_opts { } {

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

   ## INPUT globals:
   global  RELIEF_frame  BDwidth_frame  aRtext SHOWoutparms0or1 \
      PADXpx_label  PADYpx_label  RELIEF_label_lo  BDwidthPx_label \
      radbuttBKGD  RELIEF_radbutt_hi  BDwidthPx_radbutt \
      chkbuttBKGD  RELIEF_chkbutt_hi  BDwidthPx_chkbutt \
      entryBKGD  BDwidthPx_entry

   ## OUTPUT globals:
    global  curEXECOPTSframe  VARcropSide  VARcropPixels

   ## If the frame for CROP parameters is not defined yet,
   ## define the CROP frame. Also define any SUB-frames that might
   ## be needed for lines of widgets. Also define and pack the widgets.

   if {![winfo exists .fRright.fRparametersCROP]} {

      frame .fRright.fRparametersCROP   -relief $RELIEF_frame  -bd $BDwidth_frame
      frame .fRright.fRparametersCROP.fRcrop1   -relief $RELIEF_frame  -bd $BDwidth_frame
      frame .fRright.fRparametersCROP.fRcrop2   -relief $RELIEF_frame  -bd $BDwidth_frame

      ## We pack the two sub-frames here (to do it only once), but we
      ## pack the parent frame below --- doing the parent-forget-and-pack
      ## each time a CROP operation is requested by the user.

      pack .fRright.fRparametersCROP.fRcrop1 \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      pack .fRright.fRparametersCROP.fRcrop2 \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      ##+########################################################
      ## In the '.fRright.fRparametersCROP.fRcrop1' frame -
      ## DEFINE 4 RADIOBUTTON widgets, for side-for-the-crop
      ## --- along with a LABEL widget.
      ## PACK the label and radiobutton widgets.
      ##+########################################################

      label .fRright.fRparametersCROP.fRcrop1.labelCROPside \
         -text "$aRtext(labelCROPside)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      ## The radiobuttons' variable, VARcropSide, could be
      ## initialized in the additional-GUI-initialization
      ## section at the bottom of this script --- if you
      ## prefer to initialize it there.

      set VARcropSide "bottom"

      radiobutton .fRright.fRparametersCROP.fRcrop1.radbuttCROPbottom \
         -text "$aRtext(radbuttCROPbottom)" \
         -font fontTEMP_varwidth \
         -anchor w \
         -variable VARcropSide \
         -value "bottom" \
         -selectcolor "$radbuttBKGD" \
         -relief $RELIEF_radbutt_hi \
         -bd $BDwidthPx_radbutt

      radiobutton .fRright.fRparametersCROP.fRcrop1.radbuttCROPtop \
         -text "$aRtext(radbuttCROPtop)" \
         -font fontTEMP_varwidth \
         -anchor w \
         -variable VARcropSide \
         -value "top" \
         -selectcolor "$radbuttBKGD" \
         -relief $RELIEF_radbutt_hi \
         -bd $BDwidthPx_radbutt

      radiobutton .fRright.fRparametersCROP.fRcrop1.radbuttCROPleft \
         -text "$aRtext(radbuttCROPleft)" \
         -font fontTEMP_varwidth \
         -anchor w \
         -variable VARcropSide \
         -value "left" \
         -selectcolor "$radbuttBKGD" \
         -relief $RELIEF_radbutt_hi \
         -bd $BDwidthPx_radbutt

      radiobutton .fRright.fRparametersCROP.fRcrop1.radbuttCROPright \
         -text "$aRtext(radbuttCROPright)" \
         -font fontTEMP_varwidth \
         -anchor w \
         -variable VARcropSide \
         -value "right" \
         -selectcolor "$radbuttBKGD" \
         -relief $RELIEF_radbutt_hi \
         -bd $BDwidthPx_radbutt

      ## Pack the widgets in frame '.fRright.fRparametersCROP.fRcrop1'.

      pack .fRright.fRparametersCROP.fRcrop1.labelCROPside \
           .fRright.fRparametersCROP.fRcrop1.radbuttCROPbottom \
           .fRright.fRparametersCROP.fRcrop1.radbuttCROPtop \
           .fRright.fRparametersCROP.fRcrop1.radbuttCROPleft \
           .fRright.fRparametersCROP.fRcrop1.radbuttCROPright \
         -side left \
         -anchor w \
         -fill none \
         -expand 0


      ##+########################################################
      ## In the '.fRright.fRparametersCROP.fRcrop2' frame -
      ## DEFINE 1 ENTRY widgets, for number-of-pixels-to-crop
      ## --- along with a LABEL widget.
      ## PACK the label and entry widgets.
      ##+########################################################

      label .fRright.fRparametersCROP.fRcrop2.labelCROPpixels \
         -text "$aRtext(labelCROPpixels)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      set VARcropPixels "15"

      entry .fRright.fRparametersCROP.fRcrop2.entryCROPpixels \
         -textvariable VARcropPixels \
         -font fontTEMP_fixedwidth \
         -width 5 \
         -bg "$entryBKGD" \
         -relief sunken \
         -bd $BDwidthPx_entry

      ## DEFINE Checkbutton for to determine whether to 'pad the crop'.

      set PAD0or1 0

      checkbutton  .fRright.fRparametersCROP.fRcrop2.chkbuttPAD \
         -text "$aRtext(chkbuttPAD)" \
         -font fontTEMP_varwidth \
         -anchor w \
         -variable PAD0or1 \
         -selectcolor "$chkbuttBKGD" \
         -relief $RELIEF_chkbutt_hi \
         -bd $BDwidthPx_chkbutt

      ## Pack the widgets in frame '.fRright.fRparametersCROP.fRcrop2'.

      pack .fRright.fRparametersCROP.fRcrop2.labelCROPpixels \
           .fRright.fRparametersCROP.fRcrop2.entryCROPpixels \
           .fRright.fRparametersCROP.fRcrop2.chkbuttPAD \
         -side left \
         -anchor w \
         -fill none \
         -expand 0

   }
   ## END OF if {![winfo exists .fRright.fRparametersCROP]}

   ## FOR TESTING:
   #  puts "proc 'show_CROP_opts' > Replacing curEXECOPTSframe: $curEXECOPTSframe"

   ## Remove the current parent 'execOpts' frame (and the frames below it,
   ## if any) and re-pack using the 'fRparametersCROP' frame.

   pack forget $curEXECOPTSframe .fRright.fRvidaud

   set SHOWoutparms0or1 0

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

   set curEXECOPTSframe ".fRright.fRparametersCROP"

   ## FOR TESTING:
   #  puts "proc 'show_CROP_opts' > 'pack forget' and re-pack was done."
   #  puts "proc 'show_CROP_opts' > curEXECOPTSframe IS: $curEXECOPTSframe"

}
## END OF PROC 'show_CROP_opts'


##+#####################################################################
## PROC 'set_CROP_cmd'
##+#####################################################################
## PURPOSE: Builds the 'ffmpeg' command for the CROP operation, using
##          'CROP' parameters from 'CROP' frames and widgets in the
##          '.fRright.fRparametersCROP' frame --- along with
##          container-video-audio parameters from other GUI widgets.
##
##          Puts the command in global variable 'ffmpegCMD'.
##
## CALLED BY:  proc 'exec_movie_operation' which is called by a click on the
##             'ExecOption' button.
##+#####################################################################
## REFERENCE: feNautilusScripts script
## '04b_1movieFile_CROP-Npixels_ffmpeg-crop-pad_toMP4-H264-AAC.sh'
## uses the following ordering of parameters to CROP a movie file
## --- and write out a movie file in MP4-H264-AAC container-video-audio
## format.
##      ffmpeg -i "$FILENAME" -f mp4 \
##         -vcodec libx264 \
##         -vpre /usr/share/ffmpeg/libx264-lossless_slow.ffpreset \
##         -crf 22 \
##         -acodec libfaac -ab 128k  -ar 22050 -ac 1 \
##         $CROPPARM $PADPARM -threads 0 "$FILEOUT"
##
## where CROPPARM and PADPARM are given by
##
## if test "$CROPTYPE" = "top"
## then
##    CROPPARM="-croptop $CROPPIXELS"
##    PADPARM="-padtop $CROPPIXELS"
## fi
##
## if test "$CROPTYPE" = "bottom"
## then
##    CROPPARM="-cropbottom $CROPPIXELS"
##    PADPARM="-padbottom $CROPPIXELS"
## fi
##
## if test "$CROPTYPE" = "left"
## then
##    CROPPARM="-cropleft $CROPPIXELS"
##    PADPARM="-padleft $CROPPIXELS"
## fi
##
## if test "$CROPTYPE" = "right"
## then
##    CROPPARM="-cropright $CROPPIXELS"
##    PADPARM="-padright $CROPPIXELS"
## fi
##
##+#####################################################################

proc set_CROP_cmd { } {

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

   ## INPUT globals:
   global INfilename OUTfilename \
      VIDEOsize VIDEOrate VIDEOcodec VIDEOotherParms \
      AUDIOchannels AUDIOcodec AUDIOotherParms \
      Nthreads CONTAINERformat \
      VARcropSide VARcropPixels PAD0or1

   ## If PAD0or1 = 1, we pad the area that was cropped with black pixels.

   ## OUTPUT globals:
   global ffmpegCMD

   if { "$VARcropSide" == "top" } {
      set CROPPARM "-croptop $VARcropPixels"
      set PADPARM  "-padtop $VARcropPixels"
   }

   if { "$VARcropSide" == "bottom" } {
      set CROPPARM "-cropbottom $VARcropPixels"
      set PADPARM  "-padbottom $VARcropPixels"
   }

   if { "$VARcropSide" == "left" } {
      set CROPPARM "-cropleft $VARcropPixels"
      set PADPARM  "-padleft $VARcropPixels"
   }

   if { "$VARcropSide" == "right" } {
      set CROPPARM "-cropright $VARcropPixels"
      set PADPARM  "-padright $VARcropPixels"
   }

   if {$PAD0or1 == 0} {
      set PADPARM ""
   }

   set ffmpegCMD "ffmpeg -i \"$INfilename\" -f $CONTAINERformat \
      -vcodec $VIDEOcodec $VIDEOotherParms \
      -acodec $AUDIOcodec -ac $AUDIOchannels $AUDIOotherParms \
      $CROPPARM $PADPARM -threads $Nthreads \"$OUTfilename\" "

}
## END OF PROC 'set_CROP_cmd'


##+#####################################################################
## PROC 'show_PROPSin_opts'
##+#####################################################################
## PURPOSE: Loads appropriate 'PROPERTIES-IN' frames and widgets into the
##          '.fRright.fRparametersPROPERTIESin' frame.
##
## CALLED BY: proc 'loadOptsFrame_perListboxSelection', which is called
##            by a button1-release binding on the listbox.
##+#####################################################################

proc show_PROPSin_opts { } {

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

   ## INPUT globals:
   global  RELIEF_frame  BDwidth_frame  aRtext SHOWoutparms0or1 \
      PADXpx_label  PADYpx_label  RELIEF_label_lo  BDwidthPx_label

   ## OUTPUT globals:
   global  curEXECOPTSframe

   ## If the frame for PROPERTIES-IN parameters is not defined yet,
   ## define the PROPERTIES-IN frame.
   ## Also define and pack a single label widget in that frame.

   if {![winfo exists .fRright.fRparametersPROPERTIESin]} {

      frame .fRright.fRparametersPROPERTIESin   -relief $RELIEF_frame  -bd $BDwidth_frame

      ##+########################################################
      ## In the '.fRright.fRparametersPROPERTIESin' frame -
      ## DEFINE one LABEL widget.
      ## PACK the label widget.
      ##+########################################################

      label .fRright.fRparametersPROPERTIESin.labelPROPERTIESin \
         -text "$aRtext(labelPROPERTIESin)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      ## Pack the widget in frame '.fRright.fRparametersPROPERTIESin'.

      pack .fRright.fRparametersPROPERTIESin.labelPROPERTIESin \
         -side left \
         -anchor w \
         -fill none \
         -expand 0

   }
   ## END OF if {![winfo exists .fRright.fRparametersPROPERTIESin]}

   ## FOR TESTING:
   #  puts "proc 'show_PROPSin_opts' > Replacing curEXECOPTSframe: $curEXECOPTSframe"

   ## Remove the current parent 'execOpts' frame (and the frames below it,
   ## if any) and re-pack using the 'fRparametersPROPERTIESin' parent frame.

   pack forget $curEXECOPTSframe .fRright.fRvidaud

   set SHOWoutparms0or1 0

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

   set curEXECOPTSframe ".fRright.fRparametersPROPERTIESin"

   ## FOR TESTING:
   #  puts "proc 'show_PROPSin_opts' > 'pack forget' and re-pack was done."
   #  puts "proc 'show_PROPSin_opts' > curEXECOPTSframe IS: $curEXECOPTSframe"

}
## END OF PROC 'show_PROPSin_opts'


##+#####################################################################
## PROC 'set_PROPSin_cmd'
##+#####################################################################
## We do not need this proc.
## We do not build a string 'ffmepgCMD' for this operation.
## In the proc 'exec_movie_operation', we execute the 'ffmpeg -i'
## command on $INfilename to get the properties info.
## To get around some problems with the 'ffmpeg -i' command,
## we use an 'external' shell script to get the info.
##+####################################################################


##+#####################################################################
## PROC 'show_PROPSout_opts'
##+#####################################################################
## PURPOSE: Loads appropriate 'PROPERTIES-OUT' frames and widgets into
##          the '.fRright.fRparametersPROPERTIESout' frame.
##
## CALLED BY: proc 'loadOptsFrame_perListboxSelection', which is called
##            by a button1-release binding on the listbox.
##+#####################################################################

proc show_PROPSout_opts { } {

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

   ## INPUT globals:
   global  RELIEF_frame  BDwidth_frame  aRtext SHOWoutparms0or1 \
      PADXpx_label  PADYpx_label  RELIEF_label_lo  BDwidthPx_label

   ## OUTPUT globals:
   global  curEXECOPTSframe

   ## If the frame for PROPERTIES-OUT parameters is not defined yet,
   ## define the PROPERTIES-OUT frame.
   ## Also define and pack a single label widget in that frame.

   if {![winfo exists .fRright.fRparametersPROPERTIESout]} {

      frame .fRright.fRparametersPROPERTIESout -relief $RELIEF_frame  -bd $BDwidth_frame

      ##+########################################################
      ## In the '.fRright.fRparametersPROPERTIESout' frame -
      ## DEFINE one LABEL widget.
      ## PACK the label widget.
      ##+########################################################

      label .fRright.fRparametersPROPERTIESout.labelPROPERTIESout \
         -text "$aRtext(labelPROPERTIESout)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      ## Pack the widget in frame '.fRright.fRparametersPROPERTIESout'.

      pack .fRright.fRparametersPROPERTIESout.labelPROPERTIESout \
         -side left \
         -anchor w \
         -fill none \
         -expand 0

   }
   ## END OF if {![winfo exists .fRright.fRparametersPROPERTIESout]}

   ## FOR TESTING:
   #  puts "proc 'show_PROPSout_opts' > Replacing curEXECOPTSframe: $curEXECOPTSframe"

   ## Remove the current parent 'execOpts' frame (and the frames below it,
   ## if any) and re-pack using the 'fRparametersPROPERTIESout' parent frame.

   pack forget $curEXECOPTSframe .fRright.fRvidaud

   set SHOWoutparms0or1 0

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

   set curEXECOPTSframe ".fRright.fRparametersPROPERTIESout"

   ## FOR TESTING:
   #  puts "proc 'show_PROPSout_opts' > 'pack forget' and re-pack was done."
   #  puts "proc 'show_PROPSout_opts' > curEXECOPTSframe IS: $curEXECOPTSframe"

}
## END OF PROC 'show_PROPSout_opts'


##+#####################################################################
## PROC 'set_PROPSout_cmd'
##+#####################################################################
## We do not need this proc.
## We do not build a string 'ffmepgCMD' for this operation.
## In the proc 'exec_movie_operation', we execute the 'ffmpeg -i'
## command on $OUTfilename to get the properties info.
## To get around some problems with the 'ffmpeg -i' command,
## we use an 'external' shell script to get the info.
##+####################################################################


##+#####################################################################
## PROC 'show_CONVERT_opts'
##+#####################################################################
## PURPOSE: Loads appropriate 'CONVERT' frames and widgets into the
##          '.fRright.fRparametersCONVERT' frame.
##
## CALLED BY: proc 'loadOptsFrame_perListboxSelection', which is called
##            by a button1-release binding on the listbox.
##+#####################################################################

proc show_CONVERT_opts { } {

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

   ## INPUT globals:
   global  RELIEF_frame  BDwidth_frame  aRtext SHOWoutparms0or1 \
      PADXpx_label  PADYpx_label  RELIEF_label_lo  BDwidthPx_label \
      chkbuttBKGD  RELIEF_chkbutt_hi  BDwidthPx_chkbutt

   ## OUTPUT globals:
   global  curEXECOPTSframe  RESIZE0or1  RERATE0or1

   ## If the frame for CONVERT parameters is not defined yet,
   ## define the CONVERT frame.
   ## Also define and pack a single label widget in that frame.

   if {![winfo exists .fRright.fRparametersCONVERT]} {

      frame .fRright.fRparametersCONVERT   -relief $RELIEF_frame  -bd $BDwidth_frame
      frame .fRright.fRparametersCONVERT.fRconvert1 -relief $RELIEF_frame  -bd $BDwidth_frame
      frame .fRright.fRparametersCONVERT.fRconvert2 -relief $RELIEF_frame  -bd $BDwidth_frame

      ## We pack the two sub-frames here (to do it only once), but we
      ## pack the parent frame below --- doing the parent-forget-and-pack
      ## each time a CONVERT operation is requested by the user.

      pack .fRright.fRparametersCONVERT.fRconvert1 \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      pack .fRright.fRparametersCONVERT.fRconvert2 \
         -side top \
         -anchor nw \
         -fill none \
         -expand 0

      ##+########################################################
      ## In the '.fRright.fRparametersCONVERT.fRconvert1' frame -
      ## DEFINE one LABEL widget.
      ## PACK the label widget.
      ##+########################################################

      label .fRright.fRparametersCONVERT.fRconvert1.labelCONVERT \
         -text "$aRtext(labelCONVERT)" \
         -font fontTEMP_varwidth \
         -padx $PADXpx_label \
         -pady $PADYpx_label \
         -justify left \
         -anchor w \
         -relief $RELIEF_label_lo \
         -bd $BDwidthPx_label

      ## Pack the widget in frame '.fRright.fRparametersCONVERT.fRconvert1'.

      pack .fRright.fRparametersCONVERT.fRconvert1.labelCONVERT \
         -side left \
         -anchor w \
         -fill none \
         -expand 0

      ##+########################################################
      ## In the '.fRright.fRparametersCONVERT.fRconvert2' frame -
      ## DEFINE two CHECKBUTTON widgets.
      ## PACK the two widgets.
      ##+########################################################

      ## DEFINE Checkbutton for to determine whether to use 'VIDEOsize'.

      set RESIZE0or1 0

      checkbutton  .fRright.fRparametersCONVERT.fRconvert2.chkbuttRESIZE \
         -text "$aRtext(chkbuttRESIZE)" \
         -font fontTEMP_varwidth \
         -anchor w \
         -variable RESIZE0or1 \
         -selectcolor "$chkbuttBKGD" \
         -relief $RELIEF_chkbutt_hi \
         -bd $BDwidthPx_chkbutt

      ## DEFINE Checkbutton for to determine whether to use 'VIDEOrate'.

      set RERATE0or1 0

      checkbutton  .fRright.fRparametersCONVERT.fRconvert2.chkbuttRERATE \
         -text "$aRtext(chkbuttRERATE)" \
         -font fontTEMP_varwidth \
         -anchor w \
         -variable RERATE0or1 \
         -selectcolor "$chkbuttBKGD" \
         -relief $RELIEF_chkbutt_hi \
         -bd $BDwidthPx_chkbutt

      ## Pack the 2 widgets in frame '.fRright.fRparametersCONVERT.fRconvert1'.

      pack .fRright.fRparametersCONVERT.fRconvert2.chkbuttRESIZE \
           .fRright.fRparametersCONVERT.fRconvert2.chkbuttRERATE \
         -side left \
         -anchor w \
         -fill none \
         -expand 0

   }
   ## END OF if {![winfo exists .fRright.fRparametersCONVERT]}

   ## FOR TESTING:
   #  puts "proc 'show_CONVERT_opts' > Replacing curEXECOPTSframe: $curEXECOPTSframe"

   ## Remove the current parent 'execOpts' frame (and the frames below it,
   ## if any) and re-pack using the 'fRparametersCONVERT' parent frame.

   pack forget $curEXECOPTSframe .fRright.fRvidaud

   set SHOWoutparms0or1 0

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

   set curEXECOPTSframe ".fRright.fRparametersCONVERT"

   ## FOR TESTING:
   #  puts "proc 'show_CONVERT_opts' > 'pack forget' and re-pack was done."
   #  puts "proc 'show_CONVERT_opts' > curEXECOPTSframe IS: $curEXECOPTSframe"

}
## END OF PROC 'show_CONVERT_opts'


##+#####################################################################
## PROC 'set_CONVERT_cmd'
##+#####################################################################
## PURPOSE: Builds the 'ffmpeg' command for the CONVERT operation, using
##          'CONVERT' parameters --- namely, container-video-audio
##          parameters from widgets in the 'fRvidaud' frame.
##
##          Puts the command in global variable 'ffmpegCMD'.
##
## CALLED BY:  proc 'exec_movie_operation' which is called by a click on the
##             'ExecOption' button.
##+#####################################################################
## REFERENCE: feNautilusScripts script
## '13m4f2_1movieFile_CONVERTto_MP4-H264-AAC_ffmpeg.sh'
##  uses the following ordering of parameters to CONVERT a movie file
## --- and write out a new movie file in MP4-H264-AAC
## container-video-audio format.
##
##      ffmpeg -i "$FILENAME" -f mp4 \
##         -vcodec libx264 \
##         -vpre /usr/share/ffmpeg/libx264-lossless_slow.ffpreset \
##         -crf 22 \
##         -acodec libfaac -ab 128k  -ar 22050 -ac 1 \
##         -threads 0 "$FILEOUT"
##
##  and from feNautilusScripts script
##  '07_1movieFile_SCALE-resize_WxHpixels_ffmpeg-s_toMP4-H264-AAC.sh'
##  we have the video-size parameter '-s' in
##
##   ffmpeg -i "$FILENAME" -f mp4 \
##      -vcodec libx264 \
##      -vpre /usr/share/ffmpeg/libx264-lossless_slow.ffpreset \
##      -crf 22 \
##      -acodec libfaac -ab 128k  -ar 22050 -ac 1 \
##      -s $SCALE_WxH  -threads 0  "$FILEOUT"
## and
## from a video-capture script we have the video-rate parameter '-r' in
##      -r 30
##+####################################################################

proc set_CONVERT_cmd { } {

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

   ## INPUT globals:
   global INfilename OUTfilename \
      VIDEOsize VIDEOrate VIDEOcodec VIDEOotherParms \
      AUDIOchannels AUDIOcodec AUDIOotherParms \
      Nthreads CONTAINERformat \
      RESIZE0or1 RERATE0or1

   ## OUTPUT globals:
   global ffmpegCMD


   if {$RESIZE0or1 == 1} {
      set SIZEPARM "-s $VIDEOsize"
   } else {
      set SIZEPARM ""
   }

   if {$RERATE0or1 == 1} {
      set RATEPARM "-r $VIDEOrate"
   } else {
      set RATEPARM ""
   }


   set ffmpegCMD "ffmpeg -i \"$INfilename\" \
      -f $CONTAINERformat \
      -copyts -async 1 \
      -vcodec $VIDEOcodec $VIDEOotherParms \
      $SIZEPARM $RATEPARM \
      -acodec $AUDIOcodec -ac $AUDIOchannels $AUDIOotherParms \
      -threads $Nthreads \"$OUTfilename\" "

}
## END OF PROC 'set_CONVERT_cmd'


##+#####################################################################
## PROC 'play_movie_out'
##+#####################################################################
## PURPOSE: To startup a user-selected media-player program on the
##          output filename specified on the GUI.
##
##          This is, of course, helpful to check that the new movie
##          was successfully encoded (good sound, good video).
##
## CALLED BY:  a click on the 'PlayOutMovie' button.
##+#####################################################################

proc play_movie_out { } {

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

   global OUTfilename ENTRYplayer

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

   set OUTfilename [string trim "$OUTfilename"]

   if {![file exists "$OUTfilename"]} {
      popup_msgVarWithScroll .topOUTFILE \
         "The file named in the output-movie-file field was not found."
      return
   }

   ###################################################################
   ## PLAY THE OUTPUT MOVIE FILE.
   ####################################################################
   ## FOR SOME SYNTAX NOTES on running a program via the Tcl 'exec'
   ## command, see the notes above in the 'exec_movie_operation' 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 "$OUTfilename"} 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 "$OUTfilename" &} ViewerPID ]

   if {$RETcode != 0} {
      set ERRtext \
"Proc 'play_movie_out' encountered an error on trying to play output media file
[file tail "$OUTfilename"]
in directory
[file dirname "$OUTfilename"]
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_out' ran the player program"
       puts "ENTRYplayer: $ENTRYplayer"
       puts "with input"
       puts "OUTfilename: $OUTfilename"
       puts "and got"
       puts "RETcode: $RETcode"
       puts "ViewerPID: $ViewerPID"
       puts "***********************"
       puts ""
   }


}
## END OF PROC 'play_movie_out'


##+#####################################################################
## PROC 'play_movie_in'
##+#####################################################################
## PURPOSE: To startup a user-selected media-player program on the
##          input media filename specified on the GUI.
##
##          This can be very helpful when editing a movie --- for example,
##          to get the times for the start and end of a CLIP operation.
##
## CALLED BY:  a click on the 'PlayInMovie' button.
##+#####################################################################

proc play_movie_in { } {

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

   global INfilename ENTRYplayer

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

   set INfilename [string trim "$INfilename"]

   if {![file exists "$INfilename"]} {
      popup_msgVarWithScroll .topINFILE \
         "The file named in the input-movie-file field was not found."
      return
   }

   ###################################################################
   ## PLAY THE INPUT MOVIE FILE.
   ####################################################################
   ## FOR SOME SYNTAX NOTES on running a program via the Tcl 'exec'
   ## command, see the notes above in the 'exec_movie_operation' 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 "$INfilename"} 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 "$INfilename" &} ViewerPID ]

   if {$RETcode != 0} {
      set ERRtext \
"Proc 'play_movie' encountered an error on trying to play input media file
[file tail "$INfilename"]
in directory
[file dirname "$INfilename"]
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_in' ran the player program"
       puts "ENTRYplayer: $ENTRYplayer"
       puts "with input"
       puts "INfilename: $INfilename"
       puts "and got"
       puts "RETcode: $RETcode"
       puts "ViewerPID: $ViewerPID"
       puts "***********************"
       puts ""
   }


}
## END OF PROC 'play_movie_in'


##+#####################################################################
## 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(labelVRATE1)"]
   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(labelACHANNELS1)"]
   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 widthFACTOR 0.90
   set lengthOUTPUTprompts [expr {int($widthFACTOR * $lengthOUTPUTprompts)}]
   set lengthVIDEOprompts  [expr {int($widthFACTOR * $lengthVIDEOprompts)}]
   set lengthAUDIOprompts  [expr {int($widthFACTOR * $lengthAUDIOprompts)}]
   set lengthOTHERprompts  [expr {int($widthFACTOR * $lengthOTHERprompts)}]

}
## END OF PROC 'set_width_of_labels'


##+#####################################################################
## PROC 'pack_more_outparms_frame'
##+#####################################################################
## PURPOSE: To show the 'video', 'audio', and 'other' frames of
##          the GUI if the 'MoreMovieOutParms' checkbutton is ON.
##
##          Otherwise, 'forget' the frame containing the
##          'video', 'audio', and 'other' frames.
##
## CALLED:  button1-release on the 'MoreMovieOutParms' checkbutton on the GUI
##          AND, possibly, in the Additional GUI Initialization' section
##          at the bottom of this script.
##+#####################################################################

proc pack_more_outparms_frame {} {

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

   global SHOWoutparms0or1

   ## Allow the window to resize in both x and y directions.
   wm resizable . 1 1

   if {$SHOWoutparms0or1 == 1} {

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

   } else {
      pack forget .fRright.fRvidaud
   }
   ## END OF   if {$SHOWoutparms0or1 == 1}

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

}
## END OF PROC 'pack_more_outparms_frame'


##+########################################################################
## 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 'Movie-File Edit Utility' (a front-end for 'ffmpeg') **

This utility provides a GUI for editing a movie file (the video and/or
audio streams within the movie file's 'container' format).

The GUI provides parameters to the 'ffmpeg' program which is used to
make a new movie file from the selected input movie file.


*********************
Movie File Parameters (in particular, for the output movie file)
*********************

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 (actually 'ffmpeg') does 'encoding' to make the
output movie file, and does 'decoding' to read the input movie file.

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

Also video and audio parameters (such as frame-rate and bit-rate)
that are compatible with those video and audio 'codecs' are provided
on the GUI .

The user can click on the 'MoreMovieOutParms' button to see a
stack of about 10 'frames' that contain widgets by which the user
can specify the video and audio formats and their parameters ---
for making the output movie file. These widgets contain defaults
that are determined by the 'container' format that is selected.

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 'ExecOption' button
starts up the 'ffmpeg' command.


****************************
The Basic Operating Sequence:
****************************

0) The user enters the name of a movie file at the 'input' filename
   prompt. The 'Browse..' button can be used to enter a valid
   filename in that entry field.

1) The user chooses an exec-option (such as CLIP or CROP) from the
   listbox on the left of the GUI.

   When the user clicks on a line of the listbox, a 'frame' in the
   lower part of the GUI provides input widgets (labels, entry fields,
   radiobuttons, whatever) corresponding the the operation selected.
   For example:

      -  If CLIP is selected, entry fields are provided to enter
         a start-time and a duration-time for the clipping operation.

      -  If CROP is selected, radiobutton widgets are provided to
         specify which side to crop (top, bottom, left, right)
         and an entry field is provided to enter how many pixels to crop.

2) The user can change the 'container' format for the output movie file
   by clicking on one of the 'container' radiobuttons. The GUI is
   defaulted to the Matroska container format.

   When you choose a 'container' type, various video and audio
   encoding parameters are set to be compatible with that container
   format.

   As described above, if you want to change the defaulted video and
   audio encoding formats and their parameters, you can click on the
   'MoreMovieOutParms' button and change the parameters as you wish.

3) After specifying the 'container' format (and video/audio parameters)
   for the output movie file --- and after entering the parameters
   for the chosen Movie-Operation --- click on the 'ExecOption'
   button to startup the 'ffmpeg' program.

   For most operation options (the PROPERTIES options are an exception),
   this utility runs 'ffmpeg' in an 'xterm' window. Startup and coding
   messages from 'ffmpeg' can be seen in that 'xterm' window. You may
   minimize the 'xterm' window while processing, if you do not want
   to monitor the processing messages. When processing is done, the
   'xterm' window does not close, so that you can examine messages.

4) After the output movie file has been created, click on the 'PlayOutMovie'
   button to play the new movie file. You can change the 'player'
   program that is used by changing the entry at the
   'Player for the movie file:' prompt.


NOTE1:
If you take the initial defaults for everything, the operation can be
as simple as:
   0) Select an input media file.
   1) Select an operation from the listbox.
   2) Provide parameters for the operation, in the 'ExecOpts' sub-frames.
   3) Click on the 'ExecOption' button.
   4) After the output movie file has been created, click on the
      'PlayOutMovie' button.

NOTE2:
The 'PlayInMovie' button is useful for operations such as the CLIP
option. You can play the movie in a movie-player like 'totem' or
a GUI version of 'mplayer' to determine the start-time and duration
for the 'clip' that you want to extract from the movie.


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

For most operations, 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.

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

It would not really hurt if the user changed some video or audio encoding
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(s):
*************************

You can specify a 'player' program for the input and output movie files
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 output movie file by
clicking on the 'PlayOutMovie' button.

WARNING:
I have encountered movies that would NOT play with 'vlc' or 'totem',
but they WOULD play with 'ffplay' and 'mplayer' and 'gmplayer'.
So if 'PlayOutMovie' does not work on an output file (for example,
it plays the audio but not the video), try another player.


*****************
Execution Options:
*****************

This GUI utility makes it easy to use the 'ffmpeg' program
to do some 'non-interactive' movie file editing, including
operations such as
   - extracting 'clips' from a movie
   - cropping the bottom/top/left/right of the movie image
   - showing the properties of the input movie file
   - showing the properties of the output media file
   - converting a movie file to a different format (container/video/audio)
and more-to-come:
   - changing the audio volume of a movie file
   - extracting the audio from the movie, into an 'mp3' file, say
   - removing the audio from a movie file
   - adding audio to a (soundless) movie file
   - making a 'time-lapse' movie from a given movie
   - making a new movie by 'flipping' a given movie, horizontally or vertically
   - extracting images from a given movie
   - and maybe a few more movie editing deeds.
 
Some execution options that have not been implemented yet
may be seen in the listbox, preceded with the '#' character.

Comments in the code of the Tk script that makes this GUI utility describe how
each execution-option can be implemented by providing a pair of 'procs'.


***********************************************
SETTING UP THIS UTILITY FOR EASY ICON-CLICK USE:
***********************************************

The set of files for this utility consists of a Tk script
and a shell script (to perform the PROPERTIES options):

- the main Tk script 'movieClipCropEtc_ffmpeg_FrontEnd.tk'

- the auxiliary shell script 'movieFilePROPERTIES_ffmpeg-i.sh'

Those two scripts could be put in a sub-directory of the
user's home directory --- such as \$HOME/apps/tkEditMovies.

Then the user can use his/her desktop system (such as Gnome or KDE)
to set up the main Tk script as an icon on the desktop (or in a
desktop 'panel').

Then, whenever the user wants to edit a movie file,
the user can click on the icon to startup the Tk script.


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

The video-audio-other default parameter values that appear in 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 input directory for the input movie file and the
initial, default output directory for the output movie file are
set near the bottom of the script by the statements:
   set inDIR \"\$env(HOME)\"
   set outDIR \"/tmp\"
You can edit the Tk script to change those locations.


**************************************
Sample output from an 'ffmpeg' command  (from a 'clip' edit run)
**************************************

If a user is having problems in getting a successful output movie file, the following
output from a successful 'ffmpeg' movie-edit run (a CLIP run) may be helpful.

Some 'ffmpeg' build info is at the top of the messages from 'ffmpeg' ---
up to the 'Input #0' line.

The lines between the 'Input #0' line and the 'frame=' line are the initial
messages that 'ffmpeg' puts out before starting the encoding of the output file.

The lines after the 'frame=' line are 'summary' lines that were output at
the end of the edit run.

The 'frame=' line is updated 'in place' during the encoding. 

The string 'time=7.02' in the 'frame=' line indicates that the output file
that was created is about 7 seconds in duration. (For this 12 second input file,
I specified a start-time of 00:00:05 and a duration of 00:00:07.)

The string 'frame=  219' in the 'frame=' line indicates that the output file
that was created contains 219 image frames.

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
Input #0, mpeg, from '/home/blaze/TESTfilesMOVIES/mpeg/ParkingTechnique2_320x240_12sec_MPEG1-MP2.mpeg':
  Duration: N/A, start: 0.602367, bitrate: N/A
    Stream #0.0\[0x1e0\]: Video: mpeg1video, yuv420p, 320x240 \[PAR 178:163 DAR 712:489\], 500 kb/s, 29.97 tbr,
                                                                                       90k tbn, 29.97 tbc
    Stream #0.1\[0x1c0\]: Audio: mp2, 44100 Hz, mono, s16, 96 kb/s
Output #0, matroska, to '/tmp/blaze_output_movie.mkv':
    Stream #0.0: Video: libx264, yuv420p, 320x240 \[PAR 178:163 DAR 712:489\], q=10-51, 200 kb/s, 90k tbn,
                                                                                                29.97 tbc
    Stream #0.1: Audio: pcm_s16le, 22050 Hz, mono, s16, 352 kb/s
Stream mapping:
  Stream #0.0 -> #0.0
  Stream #0.1 -> #0.1
\[libx264 @ 0x8493870\]using SAR=178/163
\[libx264 @ 0x8493870\]using cpu capabilities: MMX2 SSE2Fast FastShuffle SSEMisalign LZCNT
\[libx264 @ 0x8493870\]profile Baseline, level 1.3
Press \[q\] to stop encoding
frame=  219 fps=  0 q=-1.0 Lsize=    1285kB time=7.02 bitrate=1500.2kbits/s    
video:979kB audio:302kB global headers:0kB muxing overhead 0.271934%
\[libx264 @ 0x8493870\]slice I:1     Avg QP:21.01  size: 15063
\[libx264 @ 0x8493870\]slice P:218   Avg QP:24.48  size:  4528
\[libx264 @ 0x8493870\]mb I  I16..4:  2.3%  0.0% 97.7%
\[libx264 @ 0x8493870\]mb P  I16..4:  2.2%  0.0%  0.0%  P16..4: 81.9%  0.0%  0.0%  0.0%  0.0%    skip:15.9%
\[libx264 @ 0x8493870\]coded y,uvDC,uvAC intra:69.6% 86.8% 40.3% inter:51.0% 36.1% 10.0%
\[libx264 @ 0x8493870\]SSIM Mean Y:0.9737481
\[libx264 @ 0x8493870\]kb/s:1097.2


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

For more information on 'ffmpeg', use the commands 'man ffmpeg' and 'ffmpeg -h'.
To see the supported input and output 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 in addition to 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
concerned with 'E', encoding of the output file --- as well as 'D', decoding
the input movie file.)

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 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.

PCM = Pulse Code Modulation

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 input directory for the INPUT movie file.
##+#############################################################

set inDIR "$env(HOME)"

##+#############################################################
## Set an initial full-name for the INPUT movie file.
##+#############################################################

set INfilename "$inDIR/input_movie.xyz"

##+#############################################################
## 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 "mp4"
# 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.
##+###########################################
## The initial setting of the 'player' program,
## in variable 'ENTRYplayer', is set in the
## proc 'set_defaults_for_container', according
## to the 'container' that the user chooses for
## the output file.
##+###########################################
 
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:

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

## For the 'video' section:

.fRright.fRvidaud.fRvsize.labelVSIZE1     configure -width $lengthVIDEOprompts
.fRright.fRvidaud.fRvrate.labelVRATE1     configure -width $lengthVIDEOprompts
.fRright.fRvidaud.fRvcodec.labelVCODEC1   configure -width $lengthVIDEOprompts
.fRright.fRvidaud.fRvother.labelVOTHER    configure -width $lengthVIDEOprompts

## For the 'audio' section:

.fRright.fRvidaud.fRachannels.labelACHANNELS1 configure -width $lengthAUDIOprompts
.fRright.fRvidaud.fRacodec.labelACODEC1       configure -width $lengthAUDIOprompts
.fRright.fRvidaud.fRaother.labelAOTHER        configure -width $lengthAUDIOprompts

## For the 'other' section:

.fRright.fRvidaud.fRthreads.labelTHREADS1 configure -width $lengthOTHERprompts

##+#############################################################
## Initialize the ExecOption variable.
##+#############################################################

set VARexecOption ""


##+#############################################################
## 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) :

There is one 'external' shell script that is used to implement the 'PROPERTIES-IN' and the 'PROPERTIES-OUT' options.

It is needed because the 'ffmpeg' command has not been written to query the 'properties' of a media file in a 'smooth' way. This is explained more clearly in comments in the script, below.

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 'movieFilePROPERTIES_ffmpeg-i.sh' :
#!/bin/sh
##
## SCRIPT: movieFilePROPERTIES_ffmpeg-i.sh
##
##+#######
## PURPOSE:
## This script runs the 'ffmpeg -i' command on a filename which is provided
## to this script as its only argument.
##
## This script is meant to return several lines selected from the output
## of 'ffmpeg -i'. The lines are to be sent to standard out.
##
## Those selected lines are to provide the 'properties' of a movie file.
## Example lines to be extracted:
##
## Input #0, mpeg, from 'ParkingTechnique2_320x240_12sec_MPEG1-MP2.mpeg':
##   Duration: N/A, start: 0.602367, bitrate: N/A
##     Stream #0.0[0x1e0]: Video: mpeg1video, yuv420p, 320x240 [PAR 178:163 DAR 712:489], 500 kb/s, 29.97 tbr, 90k tbn, 29.97 tbc
##     Stream #0.1[0x1c0]: Audio: mp2, 44100 Hz, mono, s16, 96 kb/s
##
##+#########
## CALLED BY:
## This shell script is meant to be called from the Tk GUI 'wrapper'
## script --- 'movieClipCropEtc_ffmpeg_FrontEnd.tk' --- when the
## user requests the PROPERTIES of an input or output movie file.
##
##+######
## METHOD:
## It would be nice to simply call 'ffmpeg -i' via a Tcl 'exec' command
## in the Tk script. However, the 'ffmpeg -i' command throws an error
## when output is not directed to a recognized media file type ---
## and all text output goes to 'stderr' not 'stdout'.
##
## Sample output follows:
##
## $ ffmpeg -i ParkingTechnique2_320x240_12sec_MPEG1-MP2.mpeg
## 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
## Input #0, mpeg, from 'ParkingTechnique2_320x240_12sec_MPEG1-MP2.mpeg':
##   Duration: N/A, start: 0.602367, bitrate: N/A
##     Stream #0.0[0x1e0]: Video: mpeg1video, yuv420p, 320x240 [PAR 178:163 DAR 712:489], 500 kb/s, 29.97 tbr, 90k tbn, 29.97 tbc
##     Stream #0.1[0x1c0]: Audio: mp2, 44100 Hz, mono, s16, 96 kb/s
## At least one output file must be specified
##
## NOTE: The information we want is between the 'built on' line and the
## ending error message line: 'At least one output file must be specified'.
##
## There does not appear to be a way to direct these information messages and
## the ending error message to 'stdout' (even with '2>&1') in such a way that
## the Tk script does not detect an error. When Tk detects the error return code,
## there does not seem to be a way to pass 'stdout' to the Tk script.
##
## So we call on this 'external' shell script from the Tk script,
## to do the dirty work of extracting the desired lines from
## the stderr output and pass the lines back to the Tk script
## without throwing an error that would prevent the Tk script
## from accepting the lines sent to stdout.
##
## We use '2>&1' to pipe the output of 'ffmpeg -i' to a small
## 'awk' program that extracts the desired lines --- between
## the 'built on' line and the 'At least one ...' line.
##
## Since we let the output of 'awk' go to 'stdout', that becomes
## the output from this script that will be captured in the Tk script.
##
## NOTE: Piping the output of 'ffmpeg -i <filename> 2>&1' to
##          egrep 'Input|Duration|Stream'
## might work, but it may miss some output for some kinds of media/movie files.
##
##+#########
## REFERENCE:
## http://www.commandlinefu.com/commands/view/2207/get-video-information-with-ffmpeg
## 2009-05-18 
## TOPIC: Get video information with ffmpeg
##
## $ ffmpeg -i filename.flv
##
## I used an flv in my example, but it'll work on any file ffmpeg supports.
##
## It says it wants an output file [the 'At least one output' error message],
## but it tells what you want to know without one [without specifying an
## output file].
##
## Also see:
## http://stackoverflow.com/questions/11400248/using-ffmpeg-to-get-video-info-why-do-i-need-to-specify-an-output-file
## http://www.techanswerguy.com/2012/03/redirecting-ffmpeg-output-performing.html
## https://groups.google.com/forum/#!msg/nodejs/7KakLQR50_w/yEVW1-kA-boJ
## http://www.computerhope.com/forum/index.php?topic=110250.0
##########################################################################
## Started: 2014jun17 Based on a similar PROPERTIES script from the
##                    feNautilusScripts system at www.freedomenv.com.
##                    But that script uses temporary files and the
##                    'grep' and 'tail' commands instead of 'awk'.
## Changed: 2014
###########################################################################

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

#########################################
## Get the filename passed to this script.
#########################################

FILENAME="$1"

## FOR TESTING:
#  FILENAME="$HOME/TESTfilesMOVIES/mpeg/ParkingTechnique2_320x240_12sec_MPEG1-MP2.mpeg"

#########################################
## Pass a heading to stdout.
#########################################

echo "\
'ffmpeg -i' output:
##################
"

########################################################################
## Pass the output of 'ffmpeg -i "$FILENAME"' to a small awk' program
## that extracts the properties of the movie file.
########################################################################
## CAUTION: Single-quotes in comment lines of an awk script cause syntax
##          errors --- like braces in comment lines cause errors in
##          Tcl-Tk scripts.
##          Use double-quotes instead.
########################################################################

ffmpeg -i "$FILENAME" 2>&1 | awk '
BEGIN {
   KEEP=0;
   ## KEEP is a flag. It will be set to 1 when we encounter the "built on" rec.
}
{
   ################################################
   ## Hold the first 12 characters of this record,
   ## whose contents are in $0.
   ################################################

   FIELD1=substr($0,1,12)

   #########################################################################
   ## If KEEP=0 and this rec does not contain the string "built on", skip
   ## this rec (read the next one). We want to read to the "built on" rec.
   #########################################################################

   if ( FIELD1 !~ "built on" && KEEP==0) next

   #########################################################################
   ## If this rec contains the string "built on", set KEEP=1 and
   ## read the next rec.
   #########################################################################

   if ( FIELD1 ~ "built on" && KEEP==0) {
      KEEP=1
      next
   }

   #########################################################################
   ## If this rec contains the string "At least one" (as in
   ## "At least one output file must be specified"), exit.
   #########################################################################

   if ( FIELD1 ~ "At least one") {exit}

   #########################################################################
   ## If we get here, this is a record we want. Print it.
   #########################################################################

   print $0
}'
## END OF the awk script.


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/tkEditMovies.

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 edit a movie, the user can click on the icon to startup this 'front end' to the 'ffmpeg' command.


LINK TO A MOVIE EDIT EXAMPLE

On the page

Movie Capture from Computer Monitor-and-Audio - a front-end for the 'ffmpeg' command

I put a link to a movie capture (from a computer monitor) that I did with that 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.

The movie shows the 'xterm' window at the beginning and the end of the movie.

I used this movie-edit utility (the CLIP option) to clip off the beginning and the end of that movie --- making this new movie [3 ]

For the CLIP parameters, I used a start-time of 00:00:05 and a duration-time of 00:00:39. In other words, out of the 48-second input-movie, I made a 39-second output movie by extracting the clip from 00:00:05 to 00:00:44.

In making this clipped movie, I made a movie with container-video-audio format mp4-h264-mp3, while the container-video-audio format of the INPUT movie was mkv(matroska)-h264-pcm.


SOME POSSIBLE ENHANCEMENTS

As you can see in the listbox in the images above, I have implemented the following 'exec-options':

  • CLIP
  • CROP
  • PROPERTIES-IN
  • PROPERTIES-OUT
  • CONVERT

But there are about 7 more options that I plan to implement in coming months:

  • CHG-VOLUME
  • EXTRACT-AUDIO
  • REMOVE-AUDIO
  • ADD-AUDIO
  • TIME-LAPSE
  • FLIP
  • EXTRACT-IMAGES

There are many Tk scripts on my 'to do' list in the categories of

  • 3D tools
  • Math proofs/demos/animations
  • Ordinary differential equation (ODE) simulations (animations)

I will probably take a break from this 'ffmpeg'-based 'tkMovieEdit' utility for a month or two.

But I may create an 'ffmpeg'-based 'tkAudioEdit' utility, before tackling some 3D/math/ODE projects.


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'

See a 2014jun30-'UPDATE' note near the bottom of page

Movie Capture from Computer Monitor-and-Audio - a front-end for the 'ffmpeg' command

for some info on using 'avconv' instead of 'ffmpeg'.