#!/usr/bin/wish -f ## ## Tk SCRIPT NAME: monitorAndAudio_MovieCapture_ffmpeg_FrontEnd.tk ## ##+####################################################################### ## PURPOSE: This Tk script provides a GUI for using the 'ffmpeg' program ## to make a MOVIE file by capturing ## 1) VIDEO from a computer monitor ## AND ## 2) AUDIO from the computer's audio board/circuitry. ## ## The GUI is intended to make the user aware of the options ## available without the user needing to use the ## 'man ffmpeg' or 'ffmpeg -h' commands or other 'ffmpeg' ## documentation --- for example, web searches. ## ## Also the GUI is meant to provide defaults for all the ## movie-making parameters that are known to work (provided ## the necessary video and audio codec libraries are available.) ## ## The options available to the user are indicated ## by the following 'sketch' of the GUI: ## ## --------------------------------------------------------------------- ## ## NOTE ON SKETCH CONVENTION for GUI sketch below: ## ## Square-brackets indicate a comment not to be included on the GUI. ## Braces indicate a Tk 'button' widget. ## Underscores indicate a Tk 'entry' widget. ## A colon indicates that the text before the colon is on a 'label' widget. ## Capital-O indicates a Tk 'radiobutton' widget. ## Capital-X indicates a Tk 'checkbutton' widget. ## ## ## Frame ## names -------------------------------------------------------------------------------------- ## | Movie-and-Audio Movie-Capture - a front-end for the 'ffmpeg' command ## V [window title] ## -------------------------------------------------------------------------------------- ## .fRbuttons {Exit} {Help} {LaunchMovieCapture} {PlayMovie} X ShowDetailedInputParms (video,audio,other) Delay time (secs): 8__ ## ## .fRmsg 'Delay time' allows some setup time before the 'ffmpeg'-window pops up and ffmpeg starts ## capturing the screen. For example: It allows time to minimize this GUI. ## [This initial message in a label widget may be changed when the 'Launch' button is clicked.] ## ## -------------------------------------------------------------------------------------- ## .fRouthead Output File parameters: ## -------------------------------------------------------------------------------------- ## ## .fRcontainer Container format: O Matroska (.mkv) O Mpeg4 (.mp4) O Mpeg (.mpg) O Flash (.flv) O AVI (.avi) O WEBM (.webm) ## ## .fRfile Output movie filename : /tmp/${USER}_screen_capture_movie.mkv______________ {Browse...} ## ## .fRplayer Player for the movie file: totem________ Examples: totem gmplayer mplayer ffplay vlc ## ## [The following frames are shown if the 'ShowDetailedInputParms' checkbuttons is set ON.] ## ## -------------------------------------------------------------------------------------- ## .fRvideohead Video parameters: ## -------------------------------------------------------------------------------------- ## ## .fRvidsize Video size: 1024x768____ Examples: 640x480 , 800x600 , 1024x768 ## ## .fRvidoffset Offset on screen: +0,0_____ Examples: +0,0 +10,30 +100,50 Video-in format: x11grab__ ## ## .fRvsource Source (display ID): :0.0___ Examples: :0.0 :0.1 Video rate (frames/sec): 25_ ## ## .fRvcodec Video codec: libx264_____ Examples: libx264 mpeg4 mpeg1video flv ... ## ## .fRvother Other video parms: -vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset_______ ## ## ------------------------------------------------------------------------------------- ## .fRaudiohead Audio parameters: ## ------------------------------------------------------------------------------------- ## ## .fRaformat Audio format: alsa____ Examples: alsa oss Audio Channels: 1_ Examples: 1 2 ## ## .fRainterface Audio interface: pulse____ Examples: pulse hw:0,0 /dev/dsp ## ## .fRacodec Audio codec: pcm_s16le__ Examples: pcm_s16le libmp3lame libfaac vorbis ## ## .fRaother Other audio parms: -ar 22050 -ab 96k_________________________________________________ ## ## -------------------------------------------------------------------------------------- ## .fRgeneral General parameters: ## -------------------------------------------------------------------------------------- ## ## .fRthreads Threads: 1___ (to take advantage of a multi-core computer) ## ## .fRguide NOTE: This utility runs 'ffmpeg' in an 'xterm' window. Startup and coding messages from 'ffmpeg' ## can be seen in that window. Minimize the window to get it out of the way of recording. Stop the ## recording by re-opening the 'xterm' window and typing 'q'. The terminal does not close after ## 'ffmpeg' stops, so that you can examine msgs. THEN CLOSE the terminal window. The output file, ## if good, can be shown in a movie player, that you specify above. See 'Help' for details. ## [a 'label' widget] ## --------------------------------------------------------------------------------------- ## ##+############## ## GUI components: ## ## From the GUI 'sketch' above, it is seen that the GUI consists of ## ABOUT: ## ## 4 'button' widgets ## 25 'label' widgets (many are for entry fields) ## 14 'entry' widgets ## 1 'checkbutton' widget ## 6 'radiobutton' widgets ## 0 'scale' widgets ## 0 'canvas' widgets ## 0 'listbox' widgets ## 0 'text' widgets ## ##+##################################################################### ## CALLED BY: This script could be put in a sub-directory of the ## users home directory, such as ## $HOME/apps/tkMonitorAndAudioMovieCapture. ## ## Then the user can use their desktop system (such as ## Gnome or KDE) to set up the script as an icon on the ## desktop. Then the user can click on the icon to ## startup the script. ##+######################################################################## ## STRUCTURE OF THIS CODE: ## ## 0) Set general window parms (win-name, win-position, win-color-scheme, ## fonts, widget-geom-parms, win-size-control, text-array-for-labels-etc). ## ## 1a) Define ALL frames (and sub-frames, if any). ## 1b) Pack the frames. ## ## 2) Define & pack all widgets in the frames, frame by frame. ## After all the widgets for a frame are defined, pack them in the frame. ## ## 3) Define keyboard and/or mouse/touchpad/touch-sensitive-screen 'event' ## BINDINGS, if needed. ## 4) Define PROCS, if needed. ## 5) Additional GUI INITIALIZATION (typically with one or more of ## the procs), if needed. ## ## In more detail: ## ## 1a) Define ALL frames -- and sub-frames: ## ## Top-level : ## 'fRbuttons' for Exit, Help, and Capture buttons ## 'fRmsg' for a label widget (for messages) ## 'fRouthead' for a label widget (for a heading) ## 'fRcontainer' for a label and several radiobutton widgets ## 'fRoutfile' for label-entry widgets ## 'fRplayer' for label-entry-label widgets ## 'fRvideohead' for a label widget (for a heading) ## 'fRvidsize' for label-entry-label widgets ## 'fRvidoffset' for label-entry-label widgets ## 'fRvsource' for label-entry-label widgets ## 'fRvcodec' for label-entry-label widgets ## 'fRvother' for label-entry widgets ## 'fRaudiohead' for a label widget (for a heading) ## 'fRaformat' for label-entry widgets ## 'fRainterface' for 2 label-entry widgets ## 'fRacodec' for label-entry widgets ## 'fRaother' for label-entry widgets ## 'fRotherhead' for a label widget (for a heading) ## 'fRthreads' for label-entry-label widgets ## 'fRguide' for a label widget (for usage info) ## ## About 21 frames, each about 1 or 2 characters high. ## ## 1b) Pack ALL frames, including sub-frames. ## ## 2) Define & pack all widgets in the frames -- basically going through ## frames & their interiors in left-to-right, top-to-bottom order: ## ## 3) Define bindings: See BINDINGS section below. ## ## 4) Define procs: ## ## 'launch_ffmpeg' - called by the 'LaunchCapture' button. ## ## 'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var. ## ## For other procs, see the PROCS section below. ## ## 5) Additional GUI initialization: See this section at the bottom ## of this script. ##+####################################################################### ## DEVELOPED WITH: Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october, 'Karmic Koala') ## ## $ wish ## % puts "$tcl_version $tk_version" ## ## showed ## 8.5 8.5 ## but this script should work in most previous 8.x versions, and probably ## even in some 7.x versions (if font handling is made 'old-style'). ##+######################################################################## ## MAINTENANCE HISTORY: ## Started by: Blaise Montandon 2014apr22 Started development, on Ubuntu 9.10, ## with the aim of getting the GUI up ## first --- procs later. ## Updated by: Blaise Montandon 2014apr24 Started implementing the procs. ## Updated by: Blaise Montandon 2014may29 Started testing. Added VIDEOrate ## entry field. ## Updated by: Blaise Montandon 2014may30 Moved Delay-time entry field from its ## own frame to the 'fRbuttons' frame. ## Added the 'fRmsg' frame and label. ##+####################################################################### ##+###################################################### ## Set WINDOW TITLE and POSITION. ##+###################################################### wm title . "Monitor-and-Audio Movie-Capture - a front end for the 'ffmpeg' command" wm iconname . "MovieCapture" wm geometry . +15+30 ##+###################################################### ## Set the COLOR SCHEME for the window and its widgets --- ## such as listbox and entry field background color. ##+###################################################### tk_setPalette "#e0e0e0" set headBKGD "#a0a0a0" set guideBKGD "#00ff00" set entryBKGD "#ffffff" set textBKGD "#f0f0f0" set radbuttBKGD "#c0c0c0" set chkbuttBKGD "#c0c0c0" # set scaleBKGD "#f0f0f0" # set listboxBKGD "#ffffff" ##+######################################################## ## DEFINE (temporary) FONT NAMES. ## ## We use a VARIABLE-WIDTH font for text on LABEL and ## BUTTON widgets. ## ## We use a FIXED-WIDTH font for LISTBOX lists, ## for text in ENTRY fields --- and often for text in ## TEXT widgets. ##+######################################################## font create fontTEMP_varwidth \ -family {comic sans ms} \ -size -14 \ -weight bold \ -slant roman font create fontTEMP_SMALL_varwidth \ -family {comic sans ms} \ -size -12 \ -weight bold \ -slant roman ## Some other possible (similar) variable width fonts: ## Arial ## Bitstream Vera Sans ## DejaVu Sans ## Droid Sans ## FreeSans ## Liberation Sans ## Nimbus Sans L ## Trebuchet MS ## Verdana font create fontTEMP_fixedwidth \ -family {liberation mono} \ -size -14 \ -weight bold \ -slant roman font create fontTEMP_SMALL_fixedwidth \ -family {liberation mono} \ -size -12 \ -weight bold \ -slant roman ## Some other possible fixed width fonts (esp. on Linux): ## Andale Mono ## Bitstream Vera Sans Mono ## Courier 10 Pitch ## DejaVu Sans Mono ## Droid Sans Mono ## FreeMono ## Nimbus Mono L ## TlwgMono ##+########################################################### ## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS. ## (e.g. width and height of canvas, and padding for Buttons) ##+########################################################### ## LABEL widget geom settings: set PADXpx_label 0 set PADYpx_label 0 set BDwidthPx_label 2 set RELIEF_label_lo "flat" ## BUTTON widget geom settings: set PADXpx_button 0 set PADYpx_button 0 set BDwidthPx_button 2 ## We use '-relief raised' for all 'button' widgets. ## ENTRY widget geom settings: set BDwidthPx_entry 2 ## We use '-relief sunken' for all 'entry' widgets. ## RADIOBUTTON widget geom settings: set PADXpx_radbutton 0 set PADYpx_radbutton 0 set BDwidthPx_radbutt 2 set RELIEF_radbutt_hi "raised" ## CHECKBUTTON widget geom settings: set PADXpx_chkbutton 0 set PADYpx_chkbutton 0 set BDwidthPx_chkbutt 2 set RELIEF_chkbutt_hi "raised" ## TEXT widget geom settings: set BDwidthPx_text 2 # set RELIEF_numtext "ridge" ## SCALE widget geom parameters: # set BDwidthPx_scale 2 # set scaleThicknessPx 10 ##+############################################################## ## Set a TEXT-ARRAY to hold text for buttons & labels on the GUI. ## NOTE: This can aid INTERNATIONALIZATION. This array can ## be set according to a nation/region parameter. ##+############################################################## ## if { "$VARlocale" == "en"} ## For '.fRbuttons' frame: set aRtext(buttonEXIT) "Exit" set aRtext(buttonHELP) "Help" set aRtext(buttonCAPTURE) "LaunchMovieCapture" set aRtext(buttonPLAY) "PlayMovie" set aRtext(chkbuttSHOWdetail) "ShowDetailedInputParms (video,audio,other)" set aRtext(labelDELAY) "Delay time (secs):" ## For '.fRmsg' frame: set aRtext(labelMSG) \ "'Delay time' allows some setup time before the window titled 'ffmpeg' pops up and ffmpeg starts capturing the screen. For example, the delay allows time to minimize this GUI." ## For '.fRouthead' frame: set aRtext(labelOUTHEAD) "Output File Parameters:" ## For '.fRcontainer' frame: set aRtext(labelCONTAINER) "Container format:" set aRtext(radbuttMATROSKA) "Matroska (.mkv)" set aRtext(radbuttMPEG4) "Mpeg4 (.mp4)" set aRtext(radbuttMPEG) "Mpeg (.mpg)" set aRtext(radbuttFLV) "Flash (.flv)" set aRtext(radbuttAVI) "AVI (.avi)" set aRtext(radbuttWEBM) "WEBM (.webm)" ## For '.fRoutfile' frame: set aRtext(labelOUTFILE) "Output movie filename :" ## For '.fRplayer' frame: set aRtext(labelPLAYER1) "Player for the movie file:" set aRtext(labelPLAYER2) "Examples: totem gmplayer mplayer ffplay vlc" ## For '.fRvideohead' frame: set aRtext(labelVIDEOHEAD) "Video recording parameters:" ## For '.fRvsize' frame: set aRtext(labelVSIZE1) "Video size:" set aRtext(labelVSIZE2) "Examples: 640x480 800x600 1024x768" ## For '.fRvoffset' frame: set aRtext(labelVOFFSET1) "Offset on screen:" set aRtext(labelVOFFSET2) "Examples: +0,0 +10,30 +100,50" ## For '.fRvsource' frame: set aRtext(labelVSOURCE1) "Source (display ID):" set aRtext(labelVSOURCE2) "Examples: :0.0 :0.1" set aRtext(labelVFORMAT1) "Video format:" set aRtext(labelVFORMAT2) "Examples: x11grab" ## For '.fRvcodec' frame: set aRtext(labelVCODEC1) "Video codec:" set aRtext(labelVCODEC2) "Examples: libx264 mpeg4 mpeg2video flv ... " set aRtext(labelVRATE1) "Video rate (frames/sec):" set aRtext(labelVRATE2) "Examples: 25 30 24" ## For '.fRvother' frame: set aRtext(labelVOTHER) "Other video parms:" ## For '.fRaudiohead' frame: set aRtext(labelAUDIOHEAD) "Audio recording parameters:" ## For '.fRaformat' frame: set aRtext(labelAFORMAT1) "Audio format:" set aRtext(labelAFORMAT2) "Examples: alsa oss" ## For '.fRainterface' frame: set aRtext(labelAINTERFACE1) "Audio interface (software):" set aRtext(labelAINTERFACE2) "Examples: pulse hw:0,0 /dev/dsp" set aRtext(labelACHANNELS1) "Audio channels:" set aRtext(labelACHANNELS2) "Examples: 1 2" ## For '.fRacodec' frame: set aRtext(labelACODEC1) "Audio codec:" set aRtext(labelACODEC2) "Examples: pcm_s16le libmp3lame libfaac vorbis" ## For '.fRaother' frame: set aRtext(labelAOTHER) "Other audio parameters:" ## For '.fRotherhead' frame: set aRtext(labelOTHERHEAD) "Other recording parameters:" ## For '.fRthreads' frame: set aRtext(labelTHREADS1) "Threads:" set aRtext(labelTHREADS2) "(to take advantage of a multi-core computer)" ## For '.fRguide' frame: set aRtext(labelGUIDE) \ "NOTE: This utility runs 'ffmpeg' in an 'xterm' window. Startup and coding messages from 'ffmpeg' can be seen in that window. Minimize the window to get it out of the way of recording. Stop the recording by re-opening the 'xterm' window and typing 'q'. The terminal does not close after 'ffmpeg' stops, so that you can examine msgs. THEN CLOSE the terminal window. The output file, if good, can be shown with a video player, that you specify above. See 'Help' for details." ## END OF if { "$VARlocale" == "en"} ##+###################################################################### ## Set a MIN-SIZE of the window (roughly). ## ## For WIDTH, allow for the min-width of the '.fRbuttons' frame. ## ## For HEIGHT, allow for the INITIAL stacked frames: ## 1 char high for the '.fRbuttons' frame ## 1 char high for the '.fRmsg' frame ## 1 char high for the '.fRouthead' frame ## 1 char high for the '.fRcontainer' frame ## 1 char high for the '.fRoutfile' frame ## 1 char high for the '.fRplayer' frame ##+##################################################################### ## FOR WIDTH: (allow for widgets in the '.fRbuttons' frame) set minWidthPx [font measure fontTEMP_varwidth \ " $aRtext(buttonEXIT) $aRtext(buttonHELP) $aRtext(buttonCAPTURE) \ $aRtext(buttonPLAY) $aRtext(chkbuttSHOWdetail) $aRtext(labelDELAY)"] ## We add some pixels to account for right-left-size of ## window-manager decoration (~8 pixels) and some pixels for ## frame/widget borders (~6 widgets x 4 pixels/widget = 24 pixels). set minWinWidthPx [expr {32 + $minWidthPx}] ##+################################################# ## For HEIGHT --- for ## 1 char high for the '.fRbuttons' frame ## 1 char high for the '.fRmsg' frame ## 1 char high for the '.fRouthead' frame ## 1 char high for the '.fRcontainer' frame ## 1 char high for the '.fRoutfile' frame ## 1 char high for the '.fRplayer' frame ## -------- ## 6 chars high for the 6 frames ##+################################################# set charHeightPx [font metrics fontTEMP_varwidth -linespace] set minWinHeightPx [expr {6 * $charHeightPx}] ## Add about 20 pixels for top-bottom window decoration -- ## and some pixels for top-and-bottom of frame/widget borders ## (~6 widgets x 4 pixels/widget = 24 pixels). set minWinHeightPx [expr {44 + $minWinHeightPx}] ## FOR TESTING: # puts "minWinWidthPx = $minWinWidthPx" # puts "minWinHeightPx = $minWinHeightPx" wm minsize . $minWinWidthPx $minWinHeightPx ## We may allow the window to be resizable. We pack some entry widgets ## (and the frames that contain them --- .fRoutfile, .fRvother, .fRaother) ## with '-fill x -expand 1' so that the entry widgets can be enlarged by ## enlarging the window. ## If you want to make the window un-resizable, ## you can use the following statement. # wm resizable . 0 0 ## Allow the window to resize in x-direction, but not y. wm resizable . 1 0 ##+#################################################################### ##+#################################################################### ## DEFINE *ALL* THE FRAMES: ## ## Top-level : ## '.fRbuttons' ## .... (about 18 frames, 1 char high) ## '.fRthreads' ## and ## 5 chars high for the 'fRguide' frame ## ## Sub-frames: None ##+#################################################################### ##+#################################################################### set RELIEF_frame flat set BDwidth_frame 0 ## FOR TESTING of expansion of frames (esp. during window expansion): # set RELIEF_frame raised # set BDwidth_frame 2 frame .fRbuttons -relief $RELIEF_frame -bd $BDwidth_frame # frame .fRmsg -relief $RELIEF_frame -bd $BDwidth_frame frame .fRmsg -relief raised -bd 2 frame .fRouthead -relief raised -borderwidth 2 frame .fRcontainer -relief $RELIEF_frame -bd $BDwidth_frame frame .fRoutfile -relief $RELIEF_frame -bd $BDwidth_frame frame .fRplayer -relief $RELIEF_frame -bd $BDwidth_frame frame .fRvideohead -relief raised -bd 2 frame .fRvsize -relief $RELIEF_frame -bd $BDwidth_frame frame .fRvoffset -relief $RELIEF_frame -bd $BDwidth_frame frame .fRvsource -relief $RELIEF_frame -bd $BDwidth_frame frame .fRvcodec -relief $RELIEF_frame -bd $BDwidth_frame frame .fRvother -relief $RELIEF_frame -bd $BDwidth_frame frame .fRaudiohead -relief raised -bd 2 frame .fRaformat -relief $RELIEF_frame -bd $BDwidth_frame frame .fRainterface -relief $RELIEF_frame -bd $BDwidth_frame frame .fRacodec -relief $RELIEF_frame -bd $BDwidth_frame frame .fRaother -relief $RELIEF_frame -bd $BDwidth_frame frame .fRotherhead -relief raised -bd 2 frame .fRthreads -relief $RELIEF_frame -bd $BDwidth_frame frame .fRguide -relief raised -bd 2 ##+######################################################## ## PACK *ALL* the FRAMES. ##+######################################################## pack .fRbuttons \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRmsg \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRouthead \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRcontainer \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRoutfile \ -side top \ -anchor nw \ -fill x \ -expand 1 pack .fRplayer \ -side top \ -anchor nw \ -fill x \ -expand 1 ########################################################## ## We pack the 'video, 'audio' and 'other' frames in ## proc 'pack_detail_frames' which is in the PROCS section ## below. This proc can be used to show-hide the 'detail' ## frames, via a checkbutton on the GUI. ########################################################## ## OK. All frames are defined --- and all are packed (except ## the 'detail' frames). Now for the widgets. ##+################################################################ ##+################################################################ ## START DEFINING & PACKING WIDGETS WITHIN THEIR FRAMES. ##+################################################################ ##+################################################################ ##+########################################################## ## IN THE '.fRbuttons' frame -- DEFINE several BUTTON widgets ## --- Exit, Help, LaunchMovieCapture, PlayMovie. Also DEFINE ## a CHECKBUTTON widget. And DEFINE 1 LABEL-ENTRY pair for ## 'Delay time'. ## Then PACK THE WIDGETS. ##+########################################################## button .fRbuttons.buttEXIT \ -text "$aRtext(buttonEXIT)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {exit} button .fRbuttons.buttHELP \ -text "$aRtext(buttonHELP)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {popup_msgVarWithScroll .topHelp "$HELPtext"} button .fRbuttons.buttCAPTURE \ -text "$aRtext(buttonCAPTURE)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command { .fRmsg.labelMSG configure -text "Control window will appear in $DELAYseconds secs." update idletasks capture_movie .fRmsg.labelMSG configure -text "$aRtext(labelMSG)"} button .fRbuttons.buttPLAY \ -text "$aRtext(buttonPLAY)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {play_movie} ## DEFINE Checkbuttons for Show/Hide-DetailFrames. set SHOWdetail0or1 0 checkbutton .fRbuttons.chkbuttSHOWdetail \ -text "$aRtext(chkbuttSHOWdetail)" \ -font fontTEMP_varwidth \ -anchor w \ -variable SHOWdetail0or1 \ -selectcolor "$chkbuttBKGD" \ -relief $RELIEF_chkbutt_hi \ -bd $BDwidthPx_chkbutt ## DEFINE label-and-entry widgets, for 'Delay time'. label .fRbuttons.labelDELAY \ -text "$aRtext(labelDELAY)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRbuttons.entryDELAY \ -textvariable DELAYseconds \ -bg $entryBKGD \ -width 3 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry ##+########################################## ## Pack the widgets in the '.fRbuttons' frame. ##+########################################## pack .fRbuttons.buttEXIT \ .fRbuttons.buttHELP \ .fRbuttons.buttCAPTURE \ .fRbuttons.buttPLAY \ .fRbuttons.chkbuttSHOWdetail \ .fRbuttons.labelDELAY \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRbuttons.entryDELAY \ -side left \ -anchor w \ -fill x \ -expand 0 ##+######################################################## ## IN THE '.fRmsg' frame -- DEFINE 1 LABEL widget. ## Then PACK IT. ##+######################################################## label .fRmsg.labelMSG \ -text "$aRtext(labelMSG)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label \ -bg "#ccffcc" pack .fRmsg.labelMSG \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE '.fRouthead' frame -- DEFINE 1 LABEL widget. ## Then PACK IT. ##+######################################################## label .fRouthead.labelOUTHEAD \ -text "$aRtext(labelOUTHEAD)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label \ -bg $headBKGD pack .fRouthead.labelOUTHEAD \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE '.fRcontainer' frame -- DEFINE 1 LABEL widget, ## and several RADIOBUTTON widgets. Then PACK THEM. ##+######################################################## label .fRcontainer.labelCONTAINER \ -text "$aRtext(labelCONTAINER)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## DEFINE Radiobuttons for container formats : radiobutton .fRcontainer.radbuttMATROSKA \ -text "$aRtext(radbuttMATROSKA)" \ -font fontTEMP_varwidth \ -anchor w \ -variable CONTAINERformat \ -value "matroska" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd $BDwidthPx_radbutt radiobutton .fRcontainer.radbuttMPEG4 \ -text "$aRtext(radbuttMPEG4)" \ -font fontTEMP_varwidth \ -anchor w \ -variable CONTAINERformat \ -value "mpeg4" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd $BDwidthPx_radbutt # .fRcontainer.radbuttMPEG4 configure -state disabled radiobutton .fRcontainer.radbuttMPEG \ -text "$aRtext(radbuttMPEG)" \ -font fontTEMP_varwidth \ -anchor w \ -variable CONTAINERformat \ -value "mpeg" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd $BDwidthPx_radbutt # .fRcontainer.radbuttMPEG configure -state disabled radiobutton .fRcontainer.radbuttFLV \ -text "$aRtext(radbuttFLV)" \ -font fontTEMP_varwidth \ -anchor w \ -variable CONTAINERformat \ -value "flv" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd $BDwidthPx_radbutt # .fRcontainer.radbuttFLV configure -state disabled radiobutton .fRcontainer.radbuttAVI \ -text "$aRtext(radbuttAVI)" \ -font fontTEMP_varwidth \ -anchor w \ -variable CONTAINERformat \ -value "avi" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd $BDwidthPx_radbutt # .fRcontainer.radbuttAVI configure -state disabled radiobutton .fRcontainer.radbuttWEBM \ -text "$aRtext(radbuttWEBM)" \ -font fontTEMP_varwidth \ -anchor w \ -variable CONTAINERformat \ -value "webm" \ -selectcolor "$radbuttBKGD" \ -relief flat \ -bd $BDwidthPx_radbutt .fRcontainer.radbuttWEBM configure -state disabled ## Pack the widgets in frame '.fRcontainer'. pack .fRcontainer.labelCONTAINER \ .fRcontainer.radbuttMATROSKA \ .fRcontainer.radbuttMPEG4 \ .fRcontainer.radbuttMPEG \ .fRcontainer.radbuttFLV \ .fRcontainer.radbuttAVI \ .fRcontainer.radbuttWEBM \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRoutfile' frame -- DEFINE 1 LABEL widget ## and 1 ENTRY widget. Then PACK THEM. ##+######################################################## label .fRoutfile.labelOUTFILE \ -text "$aRtext(labelOUTFILE)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRoutfile.entryOUTFILE \ -textvariable ENTRYfilename \ -bg $entryBKGD \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry ## COMMENTED OUT this 'Browse' button, for now. if {0} { button .fRoutfile.buttBROWSE \ -text "$aRtext(buttonBROWSE)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {get_outfilename} } ## PACK the widgets in the 'fRoutfile' frame. pack .fRoutfile.labelOUTFILE \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRoutfile.entryOUTFILE \ -side left \ -anchor w \ -fill x \ -expand 1 ## COMMENTED OUT this 'Browse' button, for now. if {0} { pack .fRoutfile.buttBROWSE \ -side left \ -anchor w \ -fill none \ -expand 0 } ##+######################################################## ## IN THE '.fRplayer' frame -- DEFINE a LABEL-ENTRY-LABEL ## triplet of widgets. Then PACK THEM. ##+######################################################## label .fRplayer.labelPLAYER1 \ -text "$aRtext(labelPLAYER1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRplayer.entryPLAYER \ -textvariable ENTRYplayer \ -bg $entryBKGD \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRplayer.labelPLAYER2 \ -text "$aRtext(labelPLAYER2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the 'fRplayer' frame. pack .fRplayer.labelPLAYER1 \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRplayer.entryPLAYER \ -side left \ -anchor w \ -fill x \ -expand 1 pack .fRplayer.labelPLAYER2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRvideohead' frame -- DEFINE 1 LABEL widget. ## Then PACK IT. ##+######################################################## label .fRvideohead.labelVIDEOHEAD \ -text "$aRtext(labelVIDEOHEAD)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label \ -bg $headBKGD pack .fRvideohead.labelVIDEOHEAD \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE '.fRvsize' frame -- DEFINE a LABEL-ENTRY-LABEL ## triplet of widgets. Then PACK THEM. ##+######################################################## label .fRvsize.labelVSIZE1 \ -text "$aRtext(labelVSIZE1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRvsize.entryVSIZE \ -textvariable VIDEOsize \ -bg $entryBKGD \ -width 10 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRvsize.labelVSIZE2 \ -text "$aRtext(labelVSIZE2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the 'fRvsize' frame. pack .fRvsize.labelVSIZE1 \ .fRvsize.entryVSIZE \ .fRvsize.labelVSIZE2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRvoffset' frame -- DEFINE a LABEL-ENTRY-LABEL ## triplet of widgets. Then PACK THEM. ##+######################################################## label .fRvoffset.labelVOFFSET1 \ -text "$aRtext(labelVOFFSET1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRvoffset.entryVOFFSET \ -textvariable VIDEOoffset \ -bg $entryBKGD \ -width 10 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRvoffset.labelVOFFSET2 \ -text "$aRtext(labelVOFFSET2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the 'fRvoffset' frame. pack .fRvoffset.labelVOFFSET1 \ .fRvoffset.entryVOFFSET \ .fRvoffset.labelVOFFSET2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+############################################################### ## IN THE '.fRvsource' frame -- DEFINE 2 sets of LABEL-ENTRY-LABEL ## triplets of widgets. Then PACK THEM. ##+############################################################### label .fRvsource.labelVSOURCE1 \ -text "$aRtext(labelVSOURCE1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRvsource.entryVSOURCE \ -textvariable VIDEOsource \ -bg $entryBKGD \ -width 10 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRvsource.labelVSOURCE2 \ -text "$aRtext(labelVSOURCE2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label label .fRvsource.labelVFORMAT1 \ -text "$aRtext(labelVFORMAT1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRvsource.entryVFORMAT \ -textvariable VIDEOformat \ -bg $entryBKGD \ -width 10 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRvsource.labelVFORMAT2 \ -text "$aRtext(labelVFORMAT2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the 'fRvsource' frame. pack .fRvsource.labelVSOURCE1 \ .fRvsource.entryVSOURCE \ .fRvsource.labelVSOURCE2 \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRvsource.labelVFORMAT2 \ .fRvsource.entryVFORMAT \ .fRvsource.labelVFORMAT1 \ -side right \ -anchor e \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRvcodec' frame -- DEFINE a LABEL-ENTRY-LABEL ## triplet of widgets. Then PACK THEM. ##+######################################################## label .fRvcodec.labelVCODEC1 \ -text "$aRtext(labelVCODEC1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRvcodec.entryVCODEC \ -textvariable VIDEOcodec \ -bg $entryBKGD \ -width 10 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRvcodec.labelVCODEC2 \ -text "$aRtext(labelVCODEC2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label label .fRvcodec.labelVRATE1 \ -text "$aRtext(labelVRATE1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRvcodec.entryVRATE \ -textvariable VIDEOrate \ -bg $entryBKGD \ -width 3 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRvcodec.labelVRATE2 \ -text "$aRtext(labelVRATE2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the 'fRvcodec' frame. pack .fRvcodec.labelVCODEC1 \ .fRvcodec.entryVCODEC \ .fRvcodec.labelVCODEC2 \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRvcodec.labelVRATE2 \ .fRvcodec.entryVRATE \ .fRvcodec.labelVRATE1 \ -side right \ -anchor e \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRvother' frame -- DEFINE a LABEL-ENTRY ## pair of widgets. Then PACK THEM. ##+######################################################## label .fRvother.labelVOTHER \ -text "$aRtext(labelVOTHER)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRvother.entryVOTHER \ -textvariable VIDEOotherParms \ -bg $entryBKGD \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry # -width 10 \ ## PACK the widgets in the 'fRvother' frame. pack .fRvother.labelVOTHER \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRvother.entryVOTHER \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE '.fRaudiohead' frame -- DEFINE 1 LABEL widget. ## Then PACK IT. ##+######################################################## label .fRaudiohead.labelAUDIOHEAD \ -text "$aRtext(labelAUDIOHEAD)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label \ -bg $headBKGD ## PACK the widgets in the 'fRaudiohead' frame. pack .fRaudiohead.labelAUDIOHEAD \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRaformat' frame -- DEFINE a LABEL-ENTRY-LABEL ## triplet of widgets. Then PACK THEM. ##+######################################################## label .fRaformat.labelAFORMAT1 \ -text "$aRtext(labelAFORMAT1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRaformat.entryAFORMAT \ -textvariable AUDIOformat \ -bg $entryBKGD \ -width 9 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRaformat.labelAFORMAT2 \ -text "$aRtext(labelAFORMAT2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the '.fRaformat' frame: pack .fRaformat.labelAFORMAT1 \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRaformat.entryAFORMAT \ -side left \ -anchor w \ -fill x \ -expand 0 pack .fRaformat.labelAFORMAT2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRainterface' frame -- DEFINE 2 LABEL-ENTRY-LABEL ## triplets of widgets. Then PACK THEM. ##+######################################################## label .fRainterface.labelAINTERFACE1 \ -text "$aRtext(labelAINTERFACE1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRainterface.entryAINTERFACE \ -textvariable AUDIOinterface \ -bg $entryBKGD \ -width 9 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRainterface.labelAINTERFACE2 \ -text "$aRtext(labelAINTERFACE2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label label .fRainterface.labelACHANNELS1 \ -text "$aRtext(labelACHANNELS1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRainterface.entryACHANNELS \ -textvariable AUDIOchannels \ -bg $entryBKGD \ -width 3 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRainterface.labelACHANNELS2 \ -text "$aRtext(labelACHANNELS2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the '.fRainterface' frame: pack .fRainterface.labelAINTERFACE1 \ .fRainterface.entryAINTERFACE \ .fRainterface.labelAINTERFACE2 \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRainterface.labelACHANNELS2 \ .fRainterface.entryACHANNELS \ .fRainterface.labelACHANNELS1 \ -side right \ -anchor e \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRacodec' frame -- DEFINE a LABEL-ENTRY-LABEL ## triplet of widgets. Then PACK THEM. ##+######################################################## label .fRacodec.labelACODEC1 \ -text "$aRtext(labelACODEC1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRacodec.entryACODEC \ -textvariable AUDIOcodec \ -bg $entryBKGD \ -width 10 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRacodec.labelACODEC2 \ -text "$aRtext(labelACODEC2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the '.fRacodec' frame: pack .fRacodec.labelACODEC1 \ .fRacodec.entryACODEC \ .fRacodec.labelACODEC2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRaother' frame -- DEFINE a LABEL-ENTRY pair ## of widgets. Then PACK THEM. ##+######################################################## label .fRaother.labelAOTHER \ -text "$aRtext(labelAOTHER)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRaother.entryAOTHER \ -textvariable AUDIOotherParms \ -bg $entryBKGD \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry # -width 30 \ ## PACK the widgets in the '.fRaother' frame: pack .fRaother.labelAOTHER \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRaother.entryAOTHER \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE '.fRotherhead' frame -- DEFINE 1 LABEL widget. ## Then PACK IT. ##+######################################################## label .fRotherhead.labelOTHERHEAD \ -text "$aRtext(labelOTHERHEAD)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label \ -bg $headBKGD pack .fRotherhead.labelOTHERHEAD \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE '.fRthreads' frame -- DEFINE 1 LABEL-ENTRY-LABEL ## triplet of widgets. Then PACK THEM. ##+######################################################## label .fRthreads.labelTHREADS1 \ -text "$aRtext(labelTHREADS1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRthreads.entryTHREADS \ -textvariable Nthreads \ -bg $entryBKGD \ -width 3 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRthreads.labelTHREADS2 \ -text "$aRtext(labelTHREADS2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the '.fRthreads' frame: pack .fRthreads.labelTHREADS1 \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRthreads.entryTHREADS \ -side left \ -anchor w \ -fill x \ -expand 0 pack .fRthreads.labelTHREADS2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRguide' frame -- DEFINE 1 LABEL widget. ## Then PACK IT. ##+######################################################## label .fRguide.labelGUIDE \ -text "$aRtext(labelGUIDE)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label \ -bg $guideBKGD ## PACK the widgets in the 'fRguide' frame: pack .fRguide.labelGUIDE \ -side left \ -anchor w \ -fill x \ -expand 1 ##+##################################################################### ## END OF SECTION TO DEFINE AND PACK THE GUI WIDGETS. ##+##################################################################### ##+##################################################################### ##+##################################################################### ## DEFINE BINDINGS: button1-release bindings on CONTAINER radiobuttons ##+##################################################################### ## Bindings for the 'Container' radiobuttons. bind .fRcontainer.radbuttMATROSKA \ {set_defaults_for_container matroska} bind .fRcontainer.radbuttMPEG4 \ {set_defaults_for_container mpeg4} bind .fRcontainer.radbuttMPEG \ {set_defaults_for_container mpeg} bind .fRcontainer.radbuttFLV \ {set_defaults_for_container flv} bind .fRcontainer.radbuttAVI \ {set_defaults_for_container avi} bind .fRcontainer.radbuttWEBM \ {set_defaults_for_container webm} ## Bindings for the 'ShowDetailedInputs' checkbutton. bind .fRbuttons.chkbuttSHOWdetail \ {pack_detail_frames} ##+##################################################################### ##+##################################################################### ## DEFINE PROCEDURES: ## ## 'get_filename' - called by the movie out-file 'Browse' button. ## (May not be needed, if the 'Browse' button is ## not implemented.) ## ## 'set_defaults_for_container' - called by bindings on the CONTAINER ## radiobuttons. ## ## Sets defaults for the GUI widgets for a given ## container type. ## ## 'capture_movie' - called by the 'LaunchMovieCapture' button. ## Launches the 'ffmpeg' program --- with user-selected ## recording parameters. ## ## 'play_movie' - called by the 'PlayMovie' button. ## Launches a movie 'player' program. ## ## 'pack_detail_frames' - called by button1-release binding on the ## ShowDetail checkbutton ## ## 'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var. ##+##################################################################### ##+##################################################################### ##+##################################################################### ## PROC 'get_filename' ##+##################################################################### ## PURPOSE: To get a filename to use for the output movie file. ## ## CALLED BY: the 'Browse ...' button, if implemented. ##+##################################################################### proc get_filename {} { ## INPUT globals: global env outDIR ## INPUT-OUTPUT globals: global ENTRYfilename ## Get a file name (possibly to make a mask). set fName [tk_getSaveFile -parent . -mustexist 0 \ -title "Select an output filename for the movie file." \ -initialdir "$outDIR" \ -initialfile "$ENTRYfilename" ] ## FOR TESTING: # puts "fName : $fName" ## Check if fName var is empty. if {"$fName" == ""} {return} ## Put $fName in ENTRYfilename. Reset the outDIR var. if {[file exists "$fName"]} { set ENTRYfilename "$fName" set outDIR [ get_chars_before_last / in "$ENTRYfilename" ] } } ## END OF PROC 'get_filename' ##+################################################################### ## PROC 'get_chars_before_last' - ##+################################################################### ## INPUT: A character and a string. ## Note: The "in" parameter is there only for clarity. ## ## OUTPUT: Returns all of the characters in the string "strng" that ## are BEFORE the last occurence of the characater "char". ## ## CALLED BY: proc 'get_img_filename' ##+################################################################## proc get_chars_before_last { char in strng } { set endIDX [ expr [string last $char $strng ] - 1 ] set output [ string range $strng 0 $endIDX ] ## FOR TESTING: # puts "From 'get_chars_before_last' proc:" # puts "STRING: $strng" # puts "CHAR: $char" # puts "RANGE up to LAST CHAR - start: 0 endIDX: $endIDX" return $output } ## END OF PROC 'get_chars_before_last' ##+##################################################################### ## PROC 'set_defaults_for_container' ##+##################################################################### ## PURPOSE: For a given container type, to set defaults for ## the widgets on the GUI --- esp. the entry widgets. ## ## CALLED BY: a button1-release binding on the 'container' radiobuttons ## and called once in the 'Additional GUI Initialization' ## section at the bottom of this script. ##+##################################################################### proc set_defaults_for_container { container } { ## FOR TESTING: (to dummy out this proc) # return ## INPUT globals: global outDIR env ## OUTPUT globals: global ENTRYfilename ENTRYplayer \ VIDEOsize VIDEOoffset VIDEOsource VIDEOformat VIDEOrate \ VIDEOcodec VIDEOotherParms AUDIOformat AUDIOinterface AUDIOchannels \ AUDIOcodec AUDIOotherParms DELAYseconds Nthreads ############################ ## FOR 'matroska' CONTAINER: ############################ if {"$container" == "matroska"} { set ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.mkv" set ENTRYplayer "totem" set VIDEOsize "800x600" set VIDEOoffset "+10,30" set VIDEOsource ":0.0" set VIDEOformat "x11grab" set VIDEOrate "25" set VIDEOcodec "libx264" set VIDEOotherParms "-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset" set AUDIOformat "alsa" set AUDIOinterface "pulse" set AUDIOchannels "1" set AUDIOcodec "pcm_s16le" set AUDIOotherParms "-ar 22050 -ab 96k" set DELAYseconds "3" set Nthreads "1" } ## END OF if {"$container" == "matroska"} ######################### ## FOR 'mpeg4' CONTAINER: ######################### if {"$container" == "mpeg4"} { set ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.mp4" set ENTRYplayer "totem" set VIDEOsize "800x600" set VIDEOoffset "+10,30" set VIDEOsource ":0.0" set VIDEOformat "x11grab" set VIDEOrate "25" set VIDEOcodec "libx264" set VIDEOotherParms "-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset" set AUDIOformat "alsa" set AUDIOinterface "pulse" set AUDIOchannels "1" set AUDIOcodec "libmp3lame" set AUDIOotherParms "-ar 44100 -ab 128k" set DELAYseconds "3" set Nthreads "1" } ## END OF if {"$container" == "mpeg4"} ######################### ## FOR 'mpeg4' CONTAINER: ######################### if {"$container" == "mpeg"} { set ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.mpg" set ENTRYplayer "totem" set VIDEOsize "800x600" set VIDEOoffset "+10,30" set VIDEOsource ":0.0" set VIDEOformat "x11grab" set VIDEOrate "25" set VIDEOcodec "mpeg2video" set VIDEOotherParms "-bufsize 1835k" set AUDIOformat "alsa" set AUDIOinterface "pulse" set AUDIOchannels "1" set AUDIOcodec "libmp3lame" set AUDIOotherParms "-ar 44100 -ab 128k" set DELAYseconds "3" set Nthreads "1" } ## END OF if {"$container" == "mpeg"} ######################### ## FOR 'flv' CONTAINER: ######################### if {"$container" == "flv"} { set ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.flv" set ENTRYplayer "totem" set VIDEOsize "800x600" set VIDEOoffset "+10,30" set VIDEOsource ":0.0" set VIDEOformat "x11grab" set VIDEOrate "25" set VIDEOcodec "libx264" set VIDEOotherParms "-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset" set AUDIOformat "alsa" set AUDIOinterface "pulse" set AUDIOchannels "1" set AUDIOcodec "libfaac" set AUDIOotherParms "-ar 44100 -ab 128k" set DELAYseconds "3" set Nthreads "1" } ## END OF if {"$container" == "flv"} ######################### ## FOR 'avi' CONTAINER: ######################### if {"$container" == "avi"} { set ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.avi" set ENTRYplayer "totem" set VIDEOsize "800x600" set VIDEOoffset "+10,30" set VIDEOsource ":0.0" set VIDEOformat "x11grab" set VIDEOrate "25" set VIDEOcodec "mpeg4" set VIDEOotherParms "" set AUDIOformat "alsa" set AUDIOinterface "pulse" set AUDIOchannels "1" set AUDIOcodec "libmp3lame" set AUDIOotherParms "-ar 44100 -ab 128k" set DELAYseconds "3" set Nthreads "1" } ## END OF if {"$container" == "avi"} ######################### ## FOR 'webm' CONTAINER: ######################### if {"$container" == "webm"} { ## ## REQUIRES TWO-PASSES WITH 'ffmpeg'?? ## set ENTRYfilename "$outDIR/$env(USER)_screen_capture_movie.webm" set ENTRYplayer "totem" set VIDEOsize "800x600" set VIDEOoffset "+10,30" set VIDEOsource ":0.0" set VIDEOformat "x11grab" set VIDEOrate "25" set VIDEOcodec "libvpx" set VIDEOotherParms "" set AUDIOformat "alsa" set AUDIOinterface "pulse" set AUDIOchannels "1" set AUDIOcodec "vorbis" set AUDIOotherParms "-ar 44100 -ab 128k" set DELAYseconds "3" set Nthreads "1" } ## END OF if {"$container" == "webm"} } ## END OF PROC 'set_defaults_for_container' ##+##################################################################### ## PROC 'capture_movie' ##+##################################################################### ## PURPOSE: To startup the 'ffmpeg' program to capture the video and ## audio from the computer screen and the audio circuitry --- ## and make a movie file from that input. ## ## CALLED BY: a click on the 'LaunchMovieCapture' button. ##+##################################################################### proc capture_movie { } { ## FOR TESTING: (dummy out this proc) # return ## INPUT globals: global ENTRYfilename VIDEOsize VIDEOoffset VIDEOsource VIDEOformat VIDEOrate \ VIDEOcodec VIDEOotherParms AUDIOformat AUDIOinterface AUDIOchannels \ AUDIOcodec AUDIOotherParms DELAYseconds Nthreads CONTAINERformat DIRscripts set DELAYmillisecs [expr {$DELAYseconds * 1000}] after $DELAYmillisecs ################################################################### ## MAKE THE MOVIE FILE. #################################################################### ## SOME SYNTAX NOTES on running the 'ffmpeg' program via a Tcl 'exec': #################################################################### ## On page 105 of the 4th edition of 'Practical Programming in Tcl & Tk', ## is the following quote on the Tcl 'exec' command: ## ## "The 'exec' command runs programs from your Tcl script. For example: ## set d [exec date] ## The standard output of the program is returned as the value of ## the 'exec' command. However, if the program writes to its standard ## error channel or exits with a nonzero status code, then 'exec' ## raises an error. If you do not care about the exit status, or you ## use a program that insists on writing to standard error, then you ## can use 'catch' to mask the errors: ## catch {exec program arg arg} result" ## ## Unfortunately, running a player program in 'foreground' mode ## like this makes the button widgets on the GUI unavailable --- ## in particular, the 'Stop' button ... and the 'Help' button. ## ## A 'foreground' run per page 105 of 'Practical Programming in Tcl & Tk'. ## NOT USED, because it 'locks up' the GUI. ####################################################################### ## On page 107 of the 4th edition of 'Practical Programming in Tcl & Tk', ## is the following quote on the Tcl 'exec' command and 'background' mode: ## ## "A trailing '&' causes the program to run in the background. ## In this case, the process identifier is returned by the 'exec' ## command. Otherwise, the 'exec' command blocks during execution ## of the program, and the standard output of the program is the ## return code of 'exec'." ## ## Page 83 of the same book says: ## "'catch' returns zero if there was no error caught, ## or a nonzero error code if it did catch an error." #################################################################### ## A couple of examples of using a PID (process ID) with Tcl: ## ## catch {eval exec $feREADER_text \"$FULFILname\" &} ProcessPID ## ## set RETcode [ catch {eval exec ${feDIR}/tkGUIs/shofil.tk \ ## "$FULFILname" &} ProcessPID ] ## #################################################################### ## An alternative form of trying 'exec': ## exec /bin/sh -c "$...." #################################################################### ######################################################################### ## A 'background' run per page 107 of 'Practical Programming in Tcl & Tk'. ## ## We run 'ffmpeg' in an 'xterm' window so that messages can be seen ## by the user, and so that the user can type 'q' to stop the recording. ######################################################################### ########################################################################### ## An attempt without using an external shell script: ## # set RETcode [ catch {eval exec /bin/sh -c \"xterm -bg black -fg white -hold -geometry 90x48+100+100 \ # -e ffmpeg -f $VIDEOformat -r $VIDEOrate -s $VIDEOsize \ # -i ${VIDEOsource}$VIDEOoffset -vcodec $VIDEOcodec $VIDEOotherParms \ # -f $AUDIOformat -i $AUDIOinterface -ac $AUDIOchannels -acodec $AUDIOcodec \ # -threads $Nthreads $ENTRYfilename \" &} CapturePID ] ########################################################################### ## 'eval' was used at one point here to avoid an 'unrecognized option' error ## when $VIDEOotherParms was appended to the 'ffmpeg' command. ########################################################################### ## From this particular order of the 'ffmpeg' parameters, I got the ## error: Unknown decoder 'libx264' ########################################################################### ########################################################################## ## In the following implementation using an external shell script ## (which includes the 'xterm' command), ## we *NEED* the double-quotes around several variables that may contain ## embedded spaces --- VIDEOotherParms, AUDIOotherParms, and ENTRYfilename. ########################################################################## set RETcode [ catch {exec \ $DIRscripts/ffmpeg_monitorAndAudio_MovieCapture.sh $VIDEOsize $VIDEOoffset \ $VIDEOsource $VIDEOformat $VIDEOrate $VIDEOcodec "$VIDEOotherParms" \ $AUDIOformat $AUDIOinterface $AUDIOchannels $AUDIOcodec "$AUDIOotherParms" \ $Nthreads $CONTAINERformat "$ENTRYfilename" &} CapturePID ] if {$RETcode != 0} { set ERRtext \ "Proc 'capture_movie' encountered an error on trying to make file [file tail "$ENTRYfilename"] in directory [file dirname "$ENTRYfilename"] using the 'ffmpeg' command. RETcode: $RETcode Message: $CapturePID Stopping processing." popup_msgVarWithScroll .topErr "$ERRtext" return } ## END OF if {$RETcode != 0} ## FOR TESTING: if {0} { puts "" puts "***********************" puts "PROC 'capture_movie' ran 'ffmpeg' with" puts "ENTRYfilename: $ENTRYfilename" puts "and got" puts "RETcode: $REGcode" puts "CapturePID: $CapturePID" puts "***********************" puts "" } } ## END OF PROC 'capture_movie' ##+##################################################################### ## PROC 'play_movie' ##+##################################################################### ## PURPOSE: To startup a user-selected media-player program on the ## output filename specified on the GUI. ## ## CALLED BY: a click on the 'PlayMovie' button. ##+##################################################################### proc play_movie { } { ## FOR TESTING: (dummy out this proc) # return global ENTRYfilename ENTRYplayer ####################################################### ## Remove trailing and leading blanks (if any) from the ## user entry in the filename 'entry' widget. ####################################################### set ENTRYfilename [string trim "$ENTRYfilename"] if {![file exists "$ENTRYfilename"]} { popup_msgVarWithScroll .topCount \ "Filename in entry field does not exist." return } ################################################################### ## PLAY THE MOVIE FILE. #################################################################### ## SOME SYNTAX NOTES on running the player program via a Tcl 'exec': #################################################################### ## See the notes above in the 'capture_movie' proc. #################################################################### ## A 'foreground' run per page 105 of 'Practical Programming in Tcl & Tk'. ## NOT USED, because it 'locks up' the GUI. # catch {eval exec $ENTRYplayer "$ENTRYfilename"} CatchMsg ########################################################################## ## A 'background' run per page 105 of 'Practical Programming in Tcl & Tk'. ## ## We use 'eval' to avoid a 'not found' error when we append ## some parms (or a space) to the player command. ########################################################################## set RETcode [ catch {eval exec $ENTRYplayer "$ENTRYfilename" &} ViewerPID ] if {$RETcode != 0} { set ERRtext \ "Proc 'play_movie' encountered an error on trying to show file [file tail "$ENTRYfilename"] in directory [file dirname "$ENTRYfilename"] using command '$ENTRYplayer'. RETcode: $RETcode Message: $ViewerPID Stopping processing." popup_msgVarWithScroll .topErr "$ERRtext" return } ## END OF if {$RETcode != 0} ## FOR TESTING: if {0} { puts "" puts "***********************" puts "PROC 'play_movie' ran the player program" puts "ENTRYplayer: $ENTRYplayer" puts "with input" puts "ENTRYfilename: $ENTRYfilename" puts "and got" puts "RETcode: $REGcode" puts "ViewerPID: $ViewerPID" puts "***********************" puts "" } } ## END OF PROC 'play_movie' ##+##################################################################### ## PROC 'set_width_of_labels' ##+##################################################################### ## PURPOSE: To set a nice common width of the labels on the left of ## each of the GUI sections: ## - output/container ## - video ## - audio ## - other ## according to the font being used for labels. ## ## CALLED: in the Additional GUI Initialization' section at the ## bottom of this script. ##+##################################################################### proc set_width_of_labels { } { ## FOR TESTING: (dummy out this proc) # return ## INPUT globals: global aRtext ## OUTPUT globals: global lengthOUTPUTprompts lengthVIDEOprompts lengthAUDIOprompts lengthOTHERprompts ## SET lengthOUTPUTprompts (in characters). set lengthOUTPUTprompts [string length "$aRtext(labelOUTFILE)"] set tempLENGTH [string length "$aRtext(labelPLAYER1)"] if {$tempLENGTH > $lengthOUTPUTprompts} {set lengthOUTPUTprompts $tempLENGTH} ## SET lengthVIDEOprompts (in characters). set lengthVIDEOprompts [string length "$aRtext(labelVSIZE1)"] set tempLENGTH [string length "$aRtext(labelVOFFSET1)"] if {$tempLENGTH > $lengthVIDEOprompts} {set lengthVIDEOprompts $tempLENGTH} set tempLENGTH [string length "$aRtext(labelVSOURCE1)"] if {$tempLENGTH > $lengthVIDEOprompts} {set lengthVIDEOprompts $tempLENGTH} set tempLENGTH [string length "$aRtext(labelVCODEC1)"] if {$tempLENGTH > $lengthVIDEOprompts} {set lengthVIDEOprompts $tempLENGTH} set tempLENGTH [string length "$aRtext(labelVOTHER)"] if {$tempLENGTH > $lengthVIDEOprompts} {set lengthVIDEOprompts $tempLENGTH} ## SET lengthAUDIOprompts (in characters). set lengthAUDIOprompts [string length "$aRtext(labelAFORMAT1)"] set tempLENGTH [string length "$aRtext(labelAINTERFACE1)"] if {$tempLENGTH > $lengthAUDIOprompts} {set lengthAUDIOprompts $tempLENGTH} set tempLENGTH [string length "$aRtext(labelACODEC1)"] if {$tempLENGTH > $lengthAUDIOprompts} {set lengthAUDIOprompts $tempLENGTH} set tempLENGTH [string length "$aRtext(labelAOTHER)"] if {$tempLENGTH > $lengthAUDIOprompts} {set lengthAUDIOprompts $tempLENGTH} ## SET lengthOTHERprompts (in characters). set lengthOTHERprompts [string length "$aRtext(labelTHREADS1)"] # set tempLENGTH [string length "$aRtext(????)"] # if {$tempLENGTH > $lengthOTHERprompts} {set lengthOTHERprompts $tempLENGTH} ## Adjust for typical overestimate because of variable-width font ## used for the labels. set lengthOUTPUTprompts [expr {int(0.80 * $lengthOUTPUTprompts)}] set lengthVIDEOprompts [expr {int(0.80 * $lengthVIDEOprompts)}] set lengthAUDIOprompts [expr {int(0.85 * $lengthAUDIOprompts)}] set lengthOTHERprompts [expr {int(0.85 * $lengthOTHERprompts)}] } ## END OF PROC 'set_width_of_labels' ##+##################################################################### ## PROC 'pack_detail_frames' ##+##################################################################### ## PURPOSE: To pack the 'video', 'audio', and 'other' frames of ## the GUI if the ShowDetail' checkbutton is ON. ## ## Otherwise, 'forget' the 'video', 'audio', and 'other' frames. ## ## CALLED: button1-release on a Show/Hide-Detail checkbutton on the GUI ## AND, possibly, in the Additional GUI Initialization' section ## at the bottom of this script. ##+##################################################################### proc pack_detail_frames {} { global SHOWdetail0or1 if {$SHOWdetail0or1 == 1} { pack .fRvideohead \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRvsize \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRvoffset \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRvsource \ -side top \ -anchor nw \ -fill x \ -expand 1 pack .fRvcodec \ -side top \ -anchor nw \ -fill x \ -expand 1 pack .fRvother \ -side top \ -anchor nw \ -fill x \ -expand 1 pack .fRaudiohead \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRaformat \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRainterface \ -side top \ -anchor nw \ -fill x \ -expand 1 pack .fRacodec \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRaother \ -side top \ -anchor nw \ -fill x \ -expand 1 pack .fRotherhead \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRthreads \ -side top \ -anchor nw \ -fill none \ -expand 0 pack .fRguide \ -side top \ -anchor nw \ -fill x \ -expand 1 } else { pack forget .fRvideohead .fRvsize .fRvoffset .fRvsource .fRvcodec \ .fRvother .fRaudiohead .fRaformat .fRainterface .fRacodec \ .fRaother .fRotherhead .fRthreads .fRguide } ## END OF if {$SHOWdetail0or1 == 1} } ## END OF PROC 'pack_detail_frames' ##+############################################################# ## PROC 'disable_enable_widgets' (NOT USED YET) ##+############################################################# ## PURPOSE: Disable/enable widgets (esp. entry widgets) ## based on ???. ## ## CALLED BY: Called in 'Additional GUI Initialization' section ## at the bottom of the script --- and by ## button1-release bindings on ???. ##+############################################################# proc disable_enable_widgets {} { ## FOR TESTING: (to dummy out this proc) return global SEARCHmask SEARCHfiletype if {$SEARCHmask == 0} { .fRmask.labelFILEMASK configure -state disabled .fRmask.entryFILEMASK configure -state disabled .fRmask2.labelFILEMASKexamples configure -state disabled } else { .fRmask.labelFILEMASK configure -state normal .fRmask.entryFILEMASK configure -state normal .fRmask2.labelFILEMASKexamples configure -state normal } if {$SEARCHfiletype == 0} { .fRfiletype.labelFILETYPE configure -state disabled .fRfiletype.entryFILETYPE configure -state disabled .fRfiletype2.labelFILETYPEexamples configure -state disabled } else { .fRfiletype.labelFILETYPE configure -state normal .fRfiletype.entryFILETYPE configure -state normal .fRfiletype2.labelFILETYPEexamples configure -state normal } } ## END OF proc 'disable_enable_widgets' ##+######################################################################## ## PROC 'popup_msgVarWithScroll' ##+######################################################################## ## PURPOSE: Report help or error conditions to the user. ## ## We do not use focus,grab,tkwait in this proc, ## because we use it to show help when the GUI is idle, ## and we may want the user to be able to keep the Help ## window open while doing some other things with the GUI ## such as putting a filename in the filename entry field ## or clicking on a radiobutton. ## ## For a similar proc with focus-grab-tkwait added, ## see the proc 'popup_msgVarWithScroll_wait' in a ## 3DterrainGeneratorExaminer Tk script. ## ## REFERENCE: page 602 of 'Practical Programming in Tcl and Tk', ## 4th edition, by Welch, Jones, Hobbs. ## ## ARGUMENTS: A toplevel frame name (such as .fRhelp or .fRerrmsg) ## and a variable holding text (many lines, if needed). ## ## CALLED BY: 'help' button ##+######################################################################## ## To have more control over the formatting of the message (esp. ## words per line), we use this 'toplevel-text' method, ## rather than the 'tk_dialog' method -- like on page 574 of the book ## by Hattie Schroeder & Mike Doyel,'Interactive Web Applications ## with Tcl/Tk', Appendix A "ED, the Tcl Code Editor". ##+######################################################################## proc popup_msgVarWithScroll { toplevName VARtext } { ## global fontTEMP_varwidth #; Not needed. 'wish' makes this global. ## global env # bell # bell ################################################# ## Set VARwidth & VARheight from $VARtext. ################################################# ## To get VARheight, ## split at '\n' (newlines) and count 'lines'. ################################################# set VARlist [ split $VARtext "\n" ] ## For testing: # puts "VARlist: $VARlist" set VARheight [ llength $VARlist ] ## For testing: # puts "VARheight: $VARheight" ################################################# ## To get VARwidth, ## loop through the 'lines' getting length ## of each; save max. ################################################# set VARwidth 0 ############################################# ## LOOK AT EACH LINE IN THE LIST. ############################################# foreach line $VARlist { ############################################# ## Get the length of the line. ############################################# set LINEwidth [ string length $line ] if { $LINEwidth > $VARwidth } { set VARwidth $LINEwidth } } ## END OF foreach line $VARlist ## For testing: # puts "VARwidth: $VARwidth" ############################################################### ## NOTE: VARwidth works for a fixed-width font used for the ## text widget ... BUT the programmer may need to be ## careful that the contents of VARtext are all ## countable characters by the 'string length' command. ############################################################### ##################################### ## SETUP 'TOP LEVEL' HELP WINDOW. ##################################### catch {destroy $toplevName} toplevel $toplevName # wm geometry $toplevName 600x400+100+50 wm geometry $toplevName +100+50 wm title $toplevName "Note" # wm title $toplevName "Note to $env(USER)" wm iconname $toplevName "Note" ##################################### ## In the frame '$toplevName' - ## DEFINE THE TEXT WIDGET and ## its two scrollbars --- and ## DEFINE an OK BUTTON widget. ##################################### if {$VARheight > 10} { text $toplevName.text \ -wrap none \ -font fontTEMP_fixedwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 \ -yscrollcommand "$toplevName.scrolly set" \ -xscrollcommand "$toplevName.scrollx set" scrollbar $toplevName.scrolly \ -orient vertical \ -command "$toplevName.text yview" scrollbar $toplevName.scrollx \ -orient horizontal \ -command "$toplevName.text xview" } else { text $toplevName.text \ -wrap none \ -font fontTEMP_fixedwidth \ -width $VARwidth \ -height $VARheight \ -bg "#f0f0f0" \ -relief raised \ -bd 2 } button $toplevName.butt \ -text "OK" \ -font fontTEMP_varwidth \ -command "destroy $toplevName" ############################################### ## PACK *ALL* the widgets in frame '$toplevName'. ############################################### ## Pack the bottom button BEFORE the ## bottom x-scrollbar widget, pack $toplevName.butt \ -side bottom \ -anchor center \ -fill none \ -expand 0 if {$VARheight > 10} { ## Pack the scrollbars BEFORE the text widget, ## so that the text does not monopolize the space. pack $toplevName.scrolly \ -side right \ -anchor center \ -fill y \ -expand 0 ## DO NOT USE '-expand 1' HERE on the Y-scrollbar. ## THAT ALLOWS Y-SCROLLBAR TO EXPAND AND PUTS ## BLANK SPACE BETWEEN Y-SCROLLBAR & THE TEXT AREA. pack $toplevName.scrollx \ -side bottom \ -anchor center \ -fill x \ -expand 0 ## DO NOT USE '-expand 1' HERE on the X-scrollbar. ## THAT KEEPS THE TEXT AREA FROM EXPANDING. pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } else { pack $toplevName.text \ -side top \ -anchor center \ -fill both \ -expand 1 } ##################################### ## LOAD MSG INTO TEXT WIDGET. ##################################### ## $toplevName.text delete 1.0 end $toplevName.text insert end $VARtext $toplevName.text configure -state disabled } ## END OF PROC 'popup_msgVarWithScroll' ##+######################## ## END of PROC definitions. ##+######################## ## Set HELPtext var. ##+######################## set HELPtext \ "** HELP for this 'Computer-Monitor-and-Computer-Audio Movie-Capture Utility ** This utility provides a GUI for recording video and audio from a computer, using the 'ffmpeg' program to make a movie file from the video and audio inputs. The video is recorded from the activity on the video monitor, and the audio is recorded from the audio board/circuitry of the computer. The operation can be as simple as clicking on the 'LaunchMovieCapture' button --- and then clicking on the 'PlayMovie' button, after the movie file has been created --- if you take the initial defaults. (A separate 'ffmeg' utility will be provided for recording video from a web cam, instead of from the computer monitor --- along with recording audio from audio circuitry of the computer.) Currently, this utility is set to capture video data in 'x11grab' format. So the capture requires the X11 windowing system and will only capture video data known to X11. For example, this utility may not capture OpenGL data in various windows on the desktop. ********************* Movie File Parameters ********************* Note that a movie file is composed of 3 formats: - the container format (Examples: matroska, mpeg4, mpeg, avi, webm) - the video 'codec' format (Examples: H.264, Mpeg4, Mpeg2, xvid, vp8) - the audio 'codec' format (Examples: mp3, pcm, aac, vorbis) 'codec' is an abbreviation for (en)code-and-decode. This GUI utility does 'encoding' to make the movie file. By default, the GUI for this utility is set to the 'Matroska' container format --- and the GUI is defaulted to video and audio 'codec' formats that are supported by that container format. Also video and audio parameters are provided on the GUI that are compatible with those video and audio 'codecs'. However, the knowledgeable user (knowledgeable in the mysterious ways of the 'ffmpeg' program) may wish to override some of the video and audio parameters (including the 'codecs') --- so most of the parameters on the GUI are changeable by the user. When the user has the parameters ready (for simplicity, the user may simply take the defaults), a click on the 'LaunchMovieCapture' buttons starts up the 'ffmpeg' command. ****************** The Control Window (a.k.a. the 'ffmpeg' window or the 'xterm' window) ****************** This utility runs the 'ffmpeg' command in a popup 'xterm' window, so that the user can see messages coming from the movie-making program, ffmpeg --- and so that the user can stop the recording by typing 'q' in the popup (control) window. Since the user is recording the video activity on the computer monitor, the user may have to minimize some windows out of the way --- including the GUI window of this utility --- and the 'xterm' (stop-control) window, after it pops up. NOTE: MINIMIZE the 'xterm' window; do NOT close it. If you close it, the 'ffmpeg' program is killed. It would not really hurt if the user changed some parameters and the 'ffmpeg' program failed. The 'ffmpeg' window will show error messages that may be helpful in determining a solution. The 'ffmpeg' window is 'held open' --- even when the 'ffmpeg' program ends (normally or abnormally) --- so that the user can examine messages from the program. When done with the messages, simply close the 'ffmpeg' window. ********************** Playing the Movie File ********************** You can specify a 'player' program for the movie file in an entry field near the top of the GUI. After it appears that a movie file has been created (with the output filename specified in a filename entry field on the GUI), you can try playing the movie file by clicking on the 'PlayMovie' button. ********************************* Post-Processing of the Movie File ********************************* There is a 'delay' parameter on the GUI that allows the user to specify a 'wait time' (in seconds). That 'delay time' is the time between a click on the 'LaunchMovieCapture' button and the instant that the 'ffmpeg' program is started (which is when the 'xterm' window pops up). The 'delay time' provides the user time to setup for the video and audio recording. For example, the user will probably want to minimize the GUI window of this utility so that it does not appear in the movie. However, it is quite likely that it will be hard to avoid some video or audio 'artifacts' at the beginning and at the end of the movie. Typically, the 'ffmpeg'/'xterm' window will be seen briefly at the beginning of the movie (before the user minimizes it) --- and the 'ffmpeg'/'xterm' window will be seen at the end of the movie (when the user opens it and types 'q'). The user may want to do some post-processing of the movie file --- such as clipping of some seconds from the beginning and the end. The 'ffmpeg' program can be used for things like clipping and cropping of movie files. And there are interactive video editors that can be used to edit the movie file. I plan to make a separate GUI utility that makes it easy to use the 'ffmpeg' program to do some non-interactive movie file editing such as - extracting 'clips' from a movie - cropping the bottom/top/left/right of the movie image - extracting the audio from the movie - adding audio to a soundless movie file - and maybe a few more movie editing deeds. *********************************** Some 'ffmpeg' Movie Capture Tidbits (gathered from the internet) *********************************** REFERENCE: http://ubuntuforums.org/archive/index.php/t-1392026.html 'HOWTO: Proper Screencasting on Linux' (as seen in 2011) \"...we capture audio from pulse (pulseaudio sound server) and encode it to *'lossless'* raw PCM with 2 audio channels (stereo). Then, we grab a video stream from x11 at a frame rate of 30 and a size of 1024×768 from the display :0.0 and encode it to *'lossless'* h264 using libx264. ... The resulting streams will be muxed in a Matroska container (.mkv).\" I have high-lighted the quotes around 'lossless' because when analog data is recorded in digital form, there is automatically some loss of information. \"Using '-threads 0' means automatic thread detection.\" NOTE: You might want to record one audio channel, with '-ac 1'. AND You might want use a frame rate less than 30, say 25 or even less. These changes may reduce size of the output file significantly. ---------------------------- Audio parms - pulse/alsa/oss: ---------------------------- \"Most recent Linux distributions have PulseAudio installed by default, but if your distribution does not use the pulseaudio sound system, try replacing '-f alsa -ac 2 -i pulse' with something like '-f alsa -ac 2 -i hw:0,0'. Many users of this guide reported success with the above options. You might have to change the 0,0 to match that of your sound device. You could also try '-f alsa -ac 2 -i /dev/dsp'. Other users reported success with '-f oss -ac 2 -i /dev/dsp'. Basically there are many ways to do it, and it depends on your system's sound configurations and hardware.\" ----------------------------- Controlling Pulse audio input: ----------------------------- \"To control PulseAudio input (e.g. capture application audio instead of mic) install 'pavucontrol'. Start recording with 'ffmpeg'. Start 'pavucontrol'. Go to the 'Recording' tab and you'll find 'ffmpeg' listed there. Change audio capture from 'Internal Audio Analog Stereo' to 'Monitor of Internal Audio Analog Stereo'. Now it should record system and application audio instead of microphone. This setting will be remembered. The next time you want to capture with 'ffmpeg', it will automatically start recording system audio. If you want to revert this, use 'pavucontrol' again to change back to microphone input.\" Message you may get if 'pavucontrol' is not installed: $ pavucontrol The program 'pavucontrol' is currently not installed. You can install it by typing: sudo apt-get install pavucontrol pavucontrol: command not found NOTE: You have to start an audio recording applicaton before using 'pavucontrol' to set the audio source. Otherwise, the 'Recording' panel of 'pavucontrol' shows the message 'No application is currently recording audio'. --------------- On pause/resume: --------------- \"Pause/resume screencasting isn't possible with ffmpeg yet, but you can use 'mkvmerge' to achieve the same result. You can install this program from your distribution's package management system under the package name 'mkvtoolnix', or download it from the official website http://www.bunkus.org/videotools/mkvtoolnix/. 'mkvmerge' allows you to concatenate mkv files with identically-encoded streams to a single file. Meaning that if you want to make a pause from screencasting, you'll just stop recording part 1, then start recording part 2 as another file, and finally concatenate (i.e. add) these 2 parts into a single screencast ready for final compression. You can do this for as many parts as you like. Example: mkvmerge -o complete.mkv part1.mkv +part2.mkv +part3.mkv +part4.mkv This command pruduces a video file named 'complete.mkv' that has all the parts put together in the order they were specified into on the command line. However, note that all the parts you want to concatenate must have exactly the same size/framerate/encoding parameters, otherwise it won't work. You can't add files with different encoding options to each other.\" ----------------------- Hiding the mouse cursor: ----------------------- \"To hide the mouse cursor, add '+nomouse' after ':0.0' to look like this: :0.0+nomouse \" (thanks to FakeOutdoorsman) ******************************** Changing the Defaults on the GUI ******************************** The defaults that appear on the GUI are set in a 'proc' named 'set_defaults_for_container'. You can find that proc in this Tk script and change the defaults as you wish. The initial, default output directory for the movie file is set near the bottom of the script by the statement: set outDIR \"/tmp\" You can edit the script to change that location. ************************************** Sample output from an 'ffmpeg' command (from an 'x11grab' recording) ************************************** If a user is having problems in getting a successful recording, the following output from a successful 'ffmpeg' recording run may be helpful. The lines after the 'frame=' line were output after 'q' was typed. Some 'ffmpeg' build info is at the top of the messages from 'ffmpeg'. The recording messages start at the first 'x11grab' line: FFmpeg version SVN-r19352-4:0.5+svn20090706-2ubuntu2.3, Copyright (c) 2000-2009 Fabrice Bellard, et al. configuration: --extra-version=4:0.5+svn20090706-2ubuntu2.3 --prefix=/usr --enable-avfilter --enable-avfilter-lavf --enable-vdpau --enable-bzlib --enable-libgsm --enable-libschroedinger --enable-libspeex --enable-libtheora --enable-libvorbis --enable-pthreads --enable-zlib --disable-stripping --disable-vhook --enable-gpl --enable-postproc --enable-swscale --enable-x11grab --enable-libdc1394 --extra-cflags=-I/build/buildd/ffmpeg-0.5+svn20090706/debian/include --enable-shared --disable-static libavutil 49.15. 0 / 49.15. 0 libavcodec 52.20. 0 / 52.20. 0 libavformat 52.31. 0 / 52.31. 0 libavdevice 52. 1. 0 / 52. 1. 0 libavfilter 0. 4. 0 / 0. 4. 0 libswscale 0. 7. 1 / 0. 7. 1 libpostproc 51. 2. 0 / 51. 2. 0 built on Mar 31 2011 18:50:18, gcc: 4.4.1 \[x11grab @ 0x8bb3700\]device: :0.0+10,30 -> display: :0.0 x: 10 y: 30 width: 800 height: 600 \[x11grab @ 0x8bb3700\]shared memory extension found Input #0, x11grab, from ':0.0+10,30': Duration: N/A, start: 1401482597.517237, bitrate: 384000 kb/s Stream #0.0: Video: rawvideo, rgb32, 800x600, 384000 kb/s, 25 tbr, 1000k tbn, 25 tbc \[alsa @ 0x8bbfc70\]capture with some ALSA plugins, especially dsnoop, may hang. Input #1, alsa, from 'pulse': Duration: N/A, start: 1401482596.951060, bitrate: N/A Stream #1.0: Audio: pcm_s16le, 44100 Hz, mono, s16, 705 kb/s Output #0, matroska, to '/tmp/blaze_screen_capture_movie.mkv': Stream #0.0: Video: libx264, yuv420p, 800x600, q=10-51, 200 kb/s, 90k tbn, 25 tbc Stream #0.1: Audio: pcm_s16le, 22050 Hz, mono, s16, 352 kb/s Stream mapping: Stream #0.0 -> #0.0 Stream #1.0 -> #0.1 \[libx264 @ 0x8bcda50\]using cpu capabilities: MMX2 SSE2Fast FastShuffle SSEMisalign LZCNT \[libx264 @ 0x8bcda50\]profile High 4:4:4 Predictive, level 3.1 Press \[q\] to stop encoding frame= 42 fps= 4 q=861008.9 Lsize= 705kB time=11.44 bitrate= 505.0kbits/s video:208kB audio:493kB global headers:0kB muxing overhead 0.556447% \[libx264 @ 0x8bcda50\]slice I:1 Avg QP: 0.00 size:120718 \[libx264 @ 0x8bcda50\]slice P:41 Avg QP: 0.00 size: 2247 \[libx264 @ 0x8bcda50\]mb I I16..4: 59.4% 0.0% 40.6% \[libx264 @ 0x8bcda50\]mb P I16..4: 31.6% 0.0% 0.0% P16..4: 0.6% 0.0% 0.0% 0.0% 0.0% skip:67.8% \[libx264 @ 0x8bcda50\]coded y,uvDC,uvAC intra:3.3% 2.5% 2.5% inter:0.5% 0.0% 0.0% \[libx264 @ 0x8bcda50\]kb/s:1013.6 ****************** More 'ffmpeg' info ****************** For more information on 'ffmpeg', use the commands 'man ffmpeg' and 'ffmpeg -h'. To see the supported input formats, use 'ffmpeg -formats'. The main web site is at ffmpeg.org. The 'ffmpeg -h' help points out the basic format in using the many 'ffmpeg' options: ffmpeg \[\[infile options\] -i infile\]... \{\[outfile options\] outfile\}... Even with this guideline, it can be quite challenging to formulate a non-trivial 'ffmpeg' command in such a way as to avoid terminating errors. The output from 'ffmpeg -formats' can be rather overpowering. It is more than 400 lines --- with a lot of audio and image formats as well as movie formats --- and no separation of audio and video codecs --- and no clear designation of 'container' formats. So I provide the following list of 'container formats' followed by 'video codecs', followed by 'audio codecs' --- ones that could be useful in making movie files. In the following, 'D' indicates that 'ffmpeg' will decode the format and 'E' indicates that 'ffmpeg' will encode the format. (This utility is mainly concerned with 'E', encoding --- although it does decode an X11 image format.) SOME MOVIE CONTAINER FORMATS: E 3g2 3GP2 format E 3gp 3GP format DE asf ASF format DE avi AVI format DE flv FLV format DE matroska Matroska file format E mov MOV format E mp4 MP4 format DE mpeg MPEG-1 System format DE ogg Ogg E vcd MPEG-1 System format (VCD) E vob MPEG-2 PS format (VOB) SOME MOVIE-VIDEO SOURCE FORMATS: D video4linux Video4Linux device grab D video4linux2 Video4Linux2 device grab D x11grab X11grab SOME VIDEO CODECS: DEVSD flv Flash Video (FLV) EV libx264 libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 DEVSDT mpeg1video MPEG-1 video DEVSDT mpeg2video MPEG-2 video DEVSDT mpeg4 MPEG-4 part 2 DEV D svq1 Sorenson Vector Quantizer 1 D VSD svq3 Sorenson Vector Quantizer 3 EV libtheora libtheora Theora D V theora Theora DEVSD wmv1 Windows Media Video 7 DEVSD wmv2 Windows Media Video 8 D V wmv3 Windows Media Video 9 EV libxvid libxvidcore MPEG-4 part 2 SOME AUDIO CODECS: EA libfaac libfaac AAC (Advanced Audio Codec) D A libfaad libfaad AAC (Advanced Audio Codec) EA libmp3lame libmp3lame MP3 (MPEG audio layer 3) D A mp3 MP3 (MPEG audio layer 3) D A mp1 MP1 (MPEG audio layer 1) DEA mp2 MP2 (MPEG audio layer 2) DEA pcm_s16le PCM signed 16-bit little-endian DEA vorbis Vorbis EA libvorbis libvorbis Vorbis There are many PCM formats --- signed/unsigned, big/little endian, floating, 8/16/24/32/64 bit. But the 'pcm_s16le' format is probably the most common. The fields preceding the 'ffmpeg' format and codec names have the following meanings: D Decoding available E Encoding available V/A/S Video/audio/subtitle codec S Codec supports slices D Codec supports direct rendering T Codec can handle input truncated at random locations instead of only at frame boundaries " ##+###################################################### ## ADDITIONAL GUI INITIALIZATION section. ##+###################################################### ##+############################################################# ## Set an initial output directory for the output movie file. ##+############################################################# set outDIR "/tmp" ##+################################################## ## Use the variable of the 'container' radiobuttons ## to set an initial choice of the container format. ##+################################################## set CONTAINERformat "matroska" # set CONTAINERformat "mpeg4" # set CONTAINERformat "mpeg" # set CONTAINERformat "flv" # set CONTAINERformat "avi" # set CONTAINERformat "webm" ##+########################################### ## Set the GUI widgets according to an initial ## setting of the container format. ##+########################################### set_defaults_for_container $CONTAINERformat ##+############################################################# ## Set the widths of the prompts (labels) on the left of the GUI ## --- in the 'output', 'video', 'audio', and 'other' sections. ##+############################################################# set_width_of_labels ## For the 'output' section: .fRoutfile.labelOUTFILE configure -width $lengthOUTPUTprompts .fRplayer.labelPLAYER1 configure -width $lengthOUTPUTprompts ## For the 'video' section: .fRvsize.labelVSIZE1 configure -width $lengthVIDEOprompts .fRvoffset.labelVOFFSET1 configure -width $lengthVIDEOprompts .fRvsource.labelVSOURCE1 configure -width $lengthVIDEOprompts .fRvcodec.labelVCODEC1 configure -width $lengthVIDEOprompts .fRvother.labelVOTHER configure -width $lengthVIDEOprompts ## For the 'audio' section: .fRaformat.labelAFORMAT1 configure -width $lengthAUDIOprompts .fRainterface.labelAINTERFACE1 configure -width $lengthAUDIOprompts .fRacodec.labelACODEC1 configure -width $lengthAUDIOprompts .fRaother.labelAOTHER configure -width $lengthAUDIOprompts ## For the 'other' section: .fRthreads.labelTHREADS1 configure -width $lengthOTHERprompts ##+#################################################### ## Disable/enable widgets according to intial settings. ## (Not needed, for now.) ##+#################################################### # disable_enable_widgets ##+############################################################# ## Get the directory that this Tk script is in. That will be the ## directory that any 'external' utility shell or Tk script ## should be in. ##+############################################################# ## FOR TESTING: # puts "argv0: $argv0" # set DIRscripts "." # set DIRscripts "[pwd]" # set DIRscripts "$env(HOME)/apps/tkUtils" set DIRscripts "[file dirname $argv0]"