uniquename - 2014jun02
I recently (2014may) published a utility for recording a movie from a computer monitor and the audio system of the computer --- at the page titled
Movie Capture from Computer Monitor-and-Audio - a front-end for the 'ffmpeg' command
I could have tried to make that utility also serve to record video from a webcam (in place of a computer monitor) --- BUT there are enough differences in video specifications (input device, input format, ...) and in the help text for webcam recording versus computer monitor recording that it seemed better to make a separate utility for webcam recording.
Keeping the two separate will also allow for more simplicity (less confusion) if enhancements are added in the future --- for example, in the area of input device 'discovery'.
So a webcam-and-audio recording utility is the subject of this page.
---
THE GOALS
My goals for the Tcl-Tk script for this GUI were:
*** Provide entry widgets for the approximately 14 parameters that can be specified to 'ffmpeg' in creating a movie file from a webcam. Provide working defaults for the parameters.
*** Provide an entry widget for an output filename, with a default name provided.
*** Provide an entry widget to allow the user to specify an movie-player program with which to view a completed movie file.
*** Provide a 'Launch' button to start the movie capture.
*** Provide an entry widget to allow the user to specify a 'delay time' before 'ffmpeg' is started up --- so that the user has time to do some preparation, such as looking up from starting the recording via the computer monitor, to look at the webcam and smile, before 'ffmpeg' recording is started.
*** Provide a 'Play' button to initiate playing of the completed movie file.
*** To avoid overwhelming the user with the number of recording parameters available, provide a checkbutton on the GUI to only show the video/audio/other parameters if the user requests to see them.
---
THE GUI LAYOUT
Like for the 'movie-capture-from-computer-monitor-and-audio' utility that I posted here, I made a 'text-sketch' for the GUI for this 'webcam-movie-capture' utility.
CONVENTIONS for the GUI 'text-sketch' below:
Frame names -------------------------------------------------------------------------------------- | Webcam-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 video. For example: It allows time to face the webcam and smile. [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}_webcam_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 .fRvformat Video-in format: video4linux2_- Examples: video4linux2 ('v4l2') video4linux ('v4l') .fRvsource Video Source: /dev/video0___ Examples: /dev/video0 /dev/video1 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_________________________________________________ -------------------------------------------------------------------------------------- .fRother Other 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 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 24 'label' widgets (many are for entry fields) 13 'entry' widgets 1 'checkbutton' widget 6 'radiobutton' widgets 0 'scale' widgets 0 'canvas' widgets 0 'listbox' widgets 0 'text' widgets
All but the 'label' widgets provide operating parameters/options in this utility. Hence there are about 4+13+1+6 = 24 options on this utility.
---
I should point out here that I was not especially interested in coming up with a 'beautiful utility'. I just wanted a utility that would make starting a recording session with 'ffmpeg' as simple as a click on a 'Launch' button.
I am certainly interested in making pretty GUI's --- as I have expressed on my 'bio' page at uniquename, and as my pages at Experiments in making embellished GUI's and Version 2 of a demo of THEMES for Tk GUI's, using images and colors have indicated.
But at this time, I am satisfied to implement the 'functionality', and let the 'beauty' go for a later date (when I have more beauty tools/code at hand).
SCREENSHOTS OF THE GUI
On the basis of the GUI-layout sketch above, I ended up with the GUI seen in the following image.
The operation can be as simple as clicking on the 'LaunchMovieCapture' button --- and then clicking on the 'PlayMovie' button, after the movie file has been created --- if you take the initial defaults.
Note that there are several radiobuttons that allow you to choose the 'container format' of the output file. But you can simply take the default.
(And you can change the default by changing a 'set CONTAINERformat' statement at the bottom of the Tk script.)
---
If the user wants to change (or simply check) the video and audio and 'other' parameters that are set according to a choice of the 'container format', the user can click on the 'ShowDetailedInputParms' checkbutton at the top of the GUI.
When that checkbutton is clicked, the GUI expands downward, as can be seen in the following image.
---
THE CONTAINER FORMATS
I have tested the 5 active container-format radiobuttons to confirm that the video-audio-other parameters that I have provided for each container-format do indeed result in a successful movie file capture.
So I have created '.mkv' '.mp4' '.mpg' '.flv' and '.avi' files.
I have grayed out the WEBM radiobutton. That is intended to eventually allow for creating a movie in the 'webm' format that Google is promoting. It uses a Matroska-like container format and a Vorbis audio format and a 'VP8' video format. You can see some information on the WEBM format at [L1 ].
I do not have the video codec that is needed to make that file format --- and my 2009 version of 'ffmpeg' may not be capable of creating a WEBM file. But I include most of the program code to easily implement and activate that option.
DESCRIPTION OF THE CODE
Below, I provide the Tk script code for this 'movie-capture-from-computer-webcam' utility.
I follow my usual 'canonical' structure for Tk code for this Tk script:
0) Set general window & widget parms (win-name, win-position, win-color-scheme, fonts-for-widgets, widget-geometry-parms, text-array-for-labels-etc, win-size-control). 1a) Define ALL frames (and sub-frames, if any). 1b) Pack ALL frames and sub-frames. 2) Define & pack all widgets in the frames, frame by frame. Within each frame, define ALL the widgets. Then pack the widgets. 3) Define keyboard and mouse/touchpad/touch-sensitive-screen action BINDINGS, if needed. 4) Define PROCS, if needed. 5) Additional GUI initialization (typically with one or more of the procs), if needed.
This Tk coding structure is discussed in more detail on the page A Canonical Structure for Tk Code --- and variations.
This structure makes it easy for me to find code sections --- while generating and testing a Tk script, and when looking for code snippets to include in other scripts (code re-use).
I call your attention to step-zero. One thing that I started doing in 2013 is use of a text-array for text in labels, buttons, and other widgets in the GUI. This can make it easier for people to internationalize my scripts. I will be using a text-array like this in most of my scripts in the future.
Experimenting with the GUI
As in all my scripts that use the 'pack' geometry manager (which is all of my 100-plus scripts, so far), I provide the four main pack parameters --- '-side', '-anchor', '-fill', '-expand' --- on all of the 'pack' commands for the frames and widgets.
That helps me when I am initially testing the behavior of a GUI (the various widgets within it) as I resize the main window.
I think that I have used a pretty nice choice of the 'pack' parameters. The label and button and radiobutton widgets stay fixed in size and relative-location if the window is re-sized --- while the output-filename and 'player-program' entry widgets expand/contract horizontally whenever the window is re-sized horizontally.
You can experiment with the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various frames and widgets --- to get the widget behavior that you want.
___
Additional experimentation: You might want to change the fonts used for the various GUI widgets. For example, you could change '-weight' from 'bold' to 'normal' --- or '-slant' from 'roman' to 'italic'. Or change font families.
In fact, you may NEED to change the font families, because the families I used may not be available on your computer --- and the default font that the 'wish' interpreter chooses may not be very pleasing.
I use variables to set geometry parameters of widgets --- parameters such as border-widths and padding. And I have included the '-relief' parameter on the definitions of frames and widgets. Feel free to experiment with those 'appearance' parameters as well.
If you find the gray palette of the GUI is not to your liking, you can change the value of the RGB parameter supplied to the 'tk_setPalette' command near the top of the code.
Some features in the code
There are plenty of comments in the code, to describe what most of the code-sections are doing.
You can look at the top of the PROCS section of the code to see a list of the procs used in this script, along with brief descriptions of how they are called and what they do.
The main procs are
'set_defaults_for_container' - called by bindings on the CONTAINER radiobuttons. Sets defaults for the GUI widgets for a given container type. 'capture_movie' - called by the 'LaunchMovieCapture' button. Launches the 'ffmpeg' program --- with user-selected recording parameters. Calls an external shell script whose code is provided below. 'play_movie' - called by the 'PlayMovie' button. Launches a user-selected movie 'player' program. 'pack_detail_frames' - called by button1-release binding on the ShowDetailedInputParms checkbutton. 'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
I used the following statement to allow the GUI to be expanded in the x-direction, but NOT the y-direction.
wm resizable . 1 0
It is my hope that the copious comments in the code will help Tcl-Tk coding 'newbies' get started in making GUI's like this.
Without the comments, potential young Tcler's might be tempted to return to their iPhones and iPads and iPods --- to watch 'Pets Gone Wild' videos.
#!/usr/bin/wish -f ## ## Tk SCRIPT NAME: webcamAndAudio_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 *webcam* ## 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 -------------------------------------------------------------------------------------- ## | Webcam-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 video. For example: It allows time to face the webcam and smile. ## [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}_webcam_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 ## ## .fRvformat Video-in format: video4linux2_- Examples: video4linux2 ('v4l2') video4linux ('v4l') ## ## .fRvsource Video Source: /dev/video0___ Examples: /dev/video0 /dev/video1 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_________________________________________________ ## ## -------------------------------------------------------------------------------------- ## .fRother Other 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 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 ## 24 'label' widgets (many are for entry fields) ## 13 '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/tkWebcamAndAudioMovieCapture. ## ## 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 ## 'fRvformat' 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 2014jun02 Started development, on Ubuntu 9.10, ## based on a similar Tk script: ## 'monitorAndAudio_MovieCapture_ffmpeg_FrontEnd.tk' ## Updated by: Blaise Montandon 2014 ##+####################################################################### ##+###################################################### ## Set WINDOW TITLE and POSITION. ##+###################################################### wm title . "Webcam-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 video. For example, the delay allows time to face the webcam and smile." ## 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 '.fRvformat' frame: set aRtext(labelVFORMAT1) "Video-in format:" set aRtext(labelVFORMAT2) "Examples: video4linux2 ('v4l2') video4linux ('v4l')" ## For '.fRvsource' frame: set aRtext(labelVSOURCE1) "Video source:" set aRtext(labelVSOURCE2) "Examples: /dev/video0 /dev/video1" ## 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:2,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. You may minimize the 'xterm' window while 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 .fRvformat -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. That 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 $RELIEF_radbutt_hi \ -bd $BDwidthPx_radbutt radiobutton .fRcontainer.radbuttMPEG4 \ -text "$aRtext(radbuttMPEG4)" \ -font fontTEMP_varwidth \ -anchor w \ -variable CONTAINERformat \ -value "mpeg4" \ -selectcolor "$radbuttBKGD" \ -relief $RELIEF_radbutt_hi \ -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 $RELIEF_radbutt_hi \ -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 $RELIEF_radbutt_hi \ -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 $RELIEF_radbutt_hi \ -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 $RELIEF_radbutt_hi \ -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 12 \ -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 '.fRvformat' frame -- DEFINE a LABEL-ENTRY-LABEL ## triplet of widgets. Then PACK THEM. ##+######################################################## label .fRvformat.labelVFORMAT1 \ -text "$aRtext(labelVFORMAT1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRvformat.entryVFORMAT \ -textvariable VIDEOformat \ -bg $entryBKGD \ -width 12 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRvformat.labelVFORMAT2 \ -text "$aRtext(labelVFORMAT2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the 'fRvformat' frame. pack .fRvformat.labelVFORMAT1 \ .fRvformat.entryVFORMAT \ .fRvformat.labelVFORMAT2 \ -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 12 \ -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 ## PACK the widgets in the 'fRvsource' frame. pack .fRvsource.labelVSOURCE1 \ .fRvsource.entryVSOURCE \ .fRvsource.labelVSOURCE2 \ -side left \ -anchor w \ -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 12 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRvcodec.labelVCODEC2 \ -text "$aRtext(labelVCODEC2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label label .fRvcodec.labelVRATE1 \ -text "$aRtext(labelVRATE1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRvcodec.entryVRATE \ -textvariable VIDEOrate \ -bg $entryBKGD \ -width 3 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRvcodec.labelVRATE2 \ -text "$aRtext(labelVRATE2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the 'fRvcodec' frame. pack .fRvcodec.labelVCODEC1 \ .fRvcodec.entryVCODEC \ .fRvcodec.labelVCODEC2 \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRvcodec.labelVRATE2 \ .fRvcodec.entryVRATE \ .fRvcodec.labelVRATE1 \ -side right \ -anchor e \ -fill none \ -expand 0 ##+######################################################## ## IN THE '.fRvother' frame -- DEFINE a LABEL-ENTRY ## pair of widgets. Then PACK THEM. ##+######################################################## label .fRvother.labelVOTHER \ -text "$aRtext(labelVOTHER)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRvother.entryVOTHER \ -textvariable VIDEOotherParms \ -bg $entryBKGD \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry # -width 10 \ ## PACK the widgets in the 'fRvother' frame. pack .fRvother.labelVOTHER \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRvother.entryVOTHER \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE '.fRaudiohead' frame -- DEFINE 1 LABEL widget. ## Then PACK IT. ##+######################################################## label .fRaudiohead.labelAUDIOHEAD \ -text "$aRtext(labelAUDIOHEAD)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label \ -bg $headBKGD ## PACK the widgets in the 'fRaudiohead' frame. pack .fRaudiohead.labelAUDIOHEAD \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE 'fRaformat' frame -- DEFINE a LABEL-ENTRY-LABEL ## triplet of widgets. Then PACK THEM. ##+######################################################## label .fRaformat.labelAFORMAT1 \ -text "$aRtext(labelAFORMAT1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRaformat.entryAFORMAT \ -textvariable AUDIOformat \ -bg $entryBKGD \ -width 9 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRaformat.labelAFORMAT2 \ -text "$aRtext(labelAFORMAT2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the '.fRaformat' frame: pack .fRaformat.labelAFORMAT1 \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRaformat.entryAFORMAT \ -side left \ -anchor w \ -fill x \ -expand 0 pack .fRaformat.labelAFORMAT2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRainterface' frame -- DEFINE 2 LABEL-ENTRY-LABEL ## triplets of widgets. Then PACK THEM. ##+######################################################## label .fRainterface.labelAINTERFACE1 \ -text "$aRtext(labelAINTERFACE1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRainterface.entryAINTERFACE \ -textvariable AUDIOinterface \ -bg $entryBKGD \ -width 9 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRainterface.labelAINTERFACE2 \ -text "$aRtext(labelAINTERFACE2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label label .fRainterface.labelACHANNELS1 \ -text "$aRtext(labelACHANNELS1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRainterface.entryACHANNELS \ -textvariable AUDIOchannels \ -bg $entryBKGD \ -width 3 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRainterface.labelACHANNELS2 \ -text "$aRtext(labelACHANNELS2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the '.fRainterface' frame: pack .fRainterface.labelAINTERFACE1 \ .fRainterface.entryAINTERFACE \ .fRainterface.labelAINTERFACE2 \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRainterface.labelACHANNELS2 \ .fRainterface.entryACHANNELS \ .fRainterface.labelACHANNELS1 \ -side right \ -anchor e \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRacodec' frame -- DEFINE a LABEL-ENTRY-LABEL ## triplet of widgets. Then PACK THEM. ##+######################################################## label .fRacodec.labelACODEC1 \ -text "$aRtext(labelACODEC1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRacodec.entryACODEC \ -textvariable AUDIOcodec \ -bg $entryBKGD \ -width 10 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRacodec.labelACODEC2 \ -text "$aRtext(labelACODEC2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the '.fRacodec' frame: pack .fRacodec.labelACODEC1 \ .fRacodec.entryACODEC \ .fRacodec.labelACODEC2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRaother' frame -- DEFINE a LABEL-ENTRY pair ## of widgets. Then PACK THEM. ##+######################################################## label .fRaother.labelAOTHER \ -text "$aRtext(labelAOTHER)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRaother.entryAOTHER \ -textvariable AUDIOotherParms \ -bg $entryBKGD \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry # -width 30 \ ## PACK the widgets in the '.fRaother' frame: pack .fRaother.labelAOTHER \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRaother.entryAOTHER \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE '.fRotherhead' frame -- DEFINE 1 LABEL widget. ## Then PACK IT. ##+######################################################## label .fRotherhead.labelOTHERHEAD \ -text "$aRtext(labelOTHERHEAD)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label \ -bg $headBKGD pack .fRotherhead.labelOTHERHEAD \ -side left \ -anchor w \ -fill x \ -expand 1 ##+######################################################## ## IN THE '.fRthreads' frame -- DEFINE 1 LABEL-ENTRY-LABEL ## triplet of widgets. Then PACK THEM. ##+######################################################## label .fRthreads.labelTHREADS1 \ -text "$aRtext(labelTHREADS1)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label entry .fRthreads.entryTHREADS \ -textvariable Nthreads \ -bg $entryBKGD \ -width 3 \ -font fontTEMP_fixedwidth \ -relief sunken \ -bd $BDwidthPx_entry label .fRthreads.labelTHREADS2 \ -text "$aRtext(labelTHREADS2)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label ## PACK the widgets in the '.fRthreads' frame: pack .fRthreads.labelTHREADS1 \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRthreads.entryTHREADS \ -side left \ -anchor w \ -fill x \ -expand 0 pack .fRthreads.labelTHREADS2 \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## IN THE 'fRguide' frame -- DEFINE 1 LABEL widget. ## Then PACK IT. ##+######################################################## label .fRguide.labelGUIDE \ -text "$aRtext(labelGUIDE)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_label \ -bg $guideBKGD ## PACK the widgets in the 'fRguide' frame: pack .fRguide.labelGUIDE \ -side left \ -anchor w \ -fill x \ -expand 1 ##+##################################################################### ## END OF SECTION TO DEFINE AND PACK THE GUI WIDGETS. ##+##################################################################### ##+##################################################################### ##+##################################################################### ## DEFINE BINDINGS: button1-release bindings on CONTAINER radiobuttons ##+##################################################################### ## Bindings for the 'Container' radiobuttons. bind .fRcontainer.radbuttMATROSKA <ButtonRelease-1> \ {set_defaults_for_container matroska} bind .fRcontainer.radbuttMPEG4 <ButtonRelease-1> \ {set_defaults_for_container mpeg4} bind .fRcontainer.radbuttMPEG <ButtonRelease-1> \ {set_defaults_for_container mpeg} bind .fRcontainer.radbuttFLV <ButtonRelease-1> \ {set_defaults_for_container flv} bind .fRcontainer.radbuttAVI <ButtonRelease-1> \ {set_defaults_for_container avi} bind .fRcontainer.radbuttWEBM <ButtonRelease-1> \ {set_defaults_for_container webm} ## Bindings for the 'ShowDetailedInputs' checkbutton. bind .fRbuttons.chkbuttSHOWdetail <ButtonRelease-1> \ {pack_detail_frames} ##+##################################################################### ##+##################################################################### ## DEFINE PROCEDURES: ## ## 'get_filename' - called by the movie out-file 'Browse' button. ## (Not be needed, unless the 'Browse' button is ## 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 VIDEOsource VIDEOformat VIDEOrate \ VIDEOcodec VIDEOotherParms AUDIOformat AUDIOinterface AUDIOchannels \ AUDIOcodec AUDIOotherParms DELAYseconds Nthreads ############################ ## FOR 'matroska' CONTAINER: ############################ if {"$container" == "matroska"} { set ENTRYfilename "$outDIR/$env(USER)_webcam_capture_movie.mkv" set ENTRYplayer "totem" set VIDEOsize "800x600" set VIDEOsource "/dev/video0" set VIDEOformat "video4linux2" 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 "2" set Nthreads "1" } ## END OF if {"$container" == "matroska"} ######################### ## FOR 'mpeg4' CONTAINER: ######################### if {"$container" == "mpeg4"} { set ENTRYfilename "$outDIR/$env(USER)_webcam_capture_movie.mp4" set ENTRYplayer "totem" set VIDEOsize "800x600" set VIDEOsource "/dev/video0" set VIDEOformat "video4linux2" 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 "2" set Nthreads "1" } ## END OF if {"$container" == "mpeg4"} ######################### ## FOR 'mpeg4' CONTAINER: ######################### if {"$container" == "mpeg"} { set ENTRYfilename "$outDIR/$env(USER)_webcam_capture_movie.mpg" set ENTRYplayer "totem" set VIDEOsize "800x600" set VIDEOsource "/dev/video0" set VIDEOformat "video4linux2" 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 "2" set Nthreads "1" } ## END OF if {"$container" == "mpeg"} ######################### ## FOR 'flv' CONTAINER: ######################### if {"$container" == "flv"} { set ENTRYfilename "$outDIR/$env(USER)_webcam_capture_movie.flv" set ENTRYplayer "totem" set VIDEOsize "800x600" set VIDEOsource "/dev/video0" set VIDEOformat "video4linux2" 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 "2" set Nthreads "1" } ## END OF if {"$container" == "flv"} ######################### ## FOR 'avi' CONTAINER: ######################### if {"$container" == "avi"} { set ENTRYfilename "$outDIR/$env(USER)_webcam_capture_movie.avi" set ENTRYplayer "totem" set VIDEOsize "800x600" set VIDEOsource "/dev/video0" set VIDEOformat "video4linux2" 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 "2" set Nthreads "1" } ## END OF if {"$container" == "avi"} ######################### ## FOR 'webm' CONTAINER: ######################### if {"$container" == "webm"} { ## ## REQUIRES TWO-PASSES WITH 'ffmpeg'?? ## set ENTRYfilename "$outDIR/$env(USER)_webcam_capture_movie.webm" set ENTRYplayer "totem" set VIDEOsize "800x600" set VIDEOsource "/dev/video0" set VIDEOformat "video4linux2" 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 "2" 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 webcam 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 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 alternative to the external-script method below, ## without using an external shell script: ## # set RETcode [ catch {eval exec "xterm -bg black -fg white -hold -geometry 90x48+100+100 \ # -e ffmpeg -f $VIDEOformat -r $VIDEOrate -s $VIDEOsize -i ${VIDEOsource} \ # -f $AUDIOformat -ac $AUDIOchannels -i $AUDIOinterface \ # -vcodec $VIDEOcodec $VIDEOotherParms -acodec $AUDIOcodec $AUDIOotherParms \ # -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. ########################################################################### ########################################################################## ## 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_webcamAndAudio_MovieCapture.sh $VIDEOsize \ $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(labelVFORMAT1)"] 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 .fRvformat \ -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 .fRvformat .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-Webcam-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 a webcam attached to the computer, 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' Tk FrontEnd utility has been provided for recording video from a computer monitor, instead of from a webcam --- along with recording audio from audio circuitry of the computer.) Currently, this utility is set to capture video data in 'Video-for-Linux' format. Most modern webcams provide video data in this format. ***************** The Webcam Device ***************** The webcam 'source' in this utility is defaulted to '/dev/video0', but be aware that if there are multiple video devices connected to your computer, your web camera may be associated with a different device, such as '/dev/video1'. If '/dev/video0' is not appropriate in a particular situation, the user can click on the 'ShowDetailedInputParms' button and set the 'Video source' entry field appropriately. (See the section 'Changing the Defaults on the GUI' below.) NOTE that if you have another webcam applicaton running, such as 'Cheese', you may get the following (misleading) error message in the 'xterm' window: \[video4linux2 @ 0x892f700\]Cannot find a proper format. The application apparently 'ties up' the specified device --- in this case, /dev/video0. Also NOTE that if you specify the wrong input device, you may get the following error message from 'ffmpeg': \[video4linux2 @ 0x9fd4700\]Cannot open video device /dev/video1 : No such file or directory /dev/video1: I/O error occurred ********************* 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 a webcam instead of the computer monitor, the user does NOT 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: If you want to hide the 'xterm' (stop-control) window, 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 may want to have a little time to allow for looking up from what they are doing on the computer screen to face the webcam and smile. 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. For example, there may be a second or two at the end of the movie recording when the user looks away from the webcam to look at the computer screen to end the movie capture by typing 'q' into the 'xterm' window. 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 of the movie file. The 'ffmpeg' program can be used for things like clipping and cropping of movie files. Also, 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. ******************************** 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. *********************************** Some 'ffmpeg' Movie Capture Tidbits (gathered from the internet) *********************************** The following web link was for capturing video from a computer monitor, not from a webcam. But it has some quotes worth noting --- especially concerning audio capture. 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 (audio or video) is recorded in digital form, there is automatically some loss of information. In other words, the capture is not really totally-lossless. \"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 (on a Debian-based Linux system): $ 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.\" -------------------- Other web references: -------------------- In addition to the 'ubuntuforums.org' link above, here some other links that may be of help: https://wiki.archlinux.org/index.php/FFmpeg#Recording_webcam (has many good examples) https://wiki.archlinux.org/index.php/FFmpeg#Screen_cast https://help.ubuntu.com/community/Webcam#FFmpeg http://ubuntuforums.org/showthread.php?t=2190455 https://trac.ffmpeg.org/wiki/How%20to%20capture%20a%20webcam%20input http://michaelphipps.com/capturing-video-webcam-and-audio-ffmpeg http://www.commandlinefu.com/commands/view/3495/record-audio-and-video-from-webcam-using-ffmpeg You can find many more such links by doing a web search on terms such as 'ffmpeg webcam'. ************************************** Sample output from an 'ffmpeg' command (from an 'video4linux2' 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 'video4linux2' 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 \[video4linux2 @ 0x8791700\]\[3\]Capabilities: 4000001 Input #0, video4linux2, from '/dev/video0': Duration: N/A, start: 1401738191.952591, bitrate: 192000 kb/s Stream #0.0: Video: rawvideo, yuyv422, 800x600, 192000 kb/s, 25 tbr, 1000k tbn, 25 tbc \[alsa @ 0x8792dc0\]capture with some ALSA plugins, especially dsnoop, may hang. Input #1, alsa, from 'pulse': Duration: N/A, start: 1401738191.949954, bitrate: N/A Stream #1.0: Audio: pcm_s16le, 44100 Hz, mono, s16, 705 kb/s Output #0, matroska, to '/tmp/blaze_webcam_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 @ 0x879fea0\]using cpu capabilities: MMX2 SSE2Fast FastShuffle SSEMisalign LZCNT \[libx264 @ 0x879fea0\]profile High 4:4:4 Predictive, level 3.1 Press \[q\] to stop encoding frame= 475 fps= 15 q=-1.0 Lsize= 180174kB time=31.74 bitrate=46501.0kbits/s video:178793kB audio:1367kB global headers:0kB muxing overhead 0.007963% \[libx264 @ 0x879fea0\]slice I:4 Avg QP: 0.00 size:375408 \[libx264 @ 0x879fea0\]slice P:471 Avg QP: 0.00 size:385523 \[libx264 @ 0x879fea0\]mb I I16..4: 26.6% 0.0% 73.4% \[libx264 @ 0x879fea0\]mb P I16..4: 71.5% 0.0% 0.0% P16..4: 28.5% 0.0% 0.0% 0.0% 0.0% skip: 0.0% \[libx264 @ 0x879fea0\]coded y,uvDC,uvAC intra:100.0% 100.0% 100.0% inter:100.0% 100.0% 100.0% \[libx264 @ 0x879fea0\]kb/s:77087.7 ****************** 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 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 mainly concerned with 'E', encoding --- although it does decode a Video-for-Linux 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 .fRvformat.labelVFORMAT1 configure -width $lengthVIDEOprompts .fRvsource.labelVSOURCE1 configure -width $lengthVIDEOprompts .fRvcodec.labelVCODEC1 configure -width $lengthVIDEOprompts .fRvother.labelVOTHER configure -width $lengthVIDEOprompts ## For the 'audio' section: .fRaformat.labelAFORMAT1 configure -width $lengthAUDIOprompts .fRainterface.labelAINTERFACE1 configure -width $lengthAUDIOprompts .fRacodec.labelACODEC1 configure -width $lengthAUDIOprompts .fRaother.labelAOTHER configure -width $lengthAUDIOprompts ## For the 'other' section: .fRthreads.labelTHREADS1 configure -width $lengthOTHERprompts ##+#################################################### ## Disable/enable widgets according to intial settings. ## (Not needed, for now.) ##+#################################################### # disable_enable_widgets ##+############################################################# ## Get the directory that this Tk script is in. That will be the ## directory that any 'external' utility shell or Tk script ## should be in. ##+############################################################# ## FOR TESTING: # puts "argv0: $argv0" # set DIRscripts "." # set DIRscripts "[pwd]" # set DIRscripts "$env(HOME)/apps/tkUtils" set DIRscripts "[file dirname $argv0]"
Shell script (called by the Tk script) :
And here is the code for the shell script called by this Tk script.
Having the 'ffmpeg' call in a shell script instead of embedded in the Tk script facilitates testing and debugging. For example, this script can be tested independently of the Tk script.
In fact, this shell script could be modified to serve as a 'hard-coded' means of recording webcam sessions.
You can put this script in the same directory with the Tk script. The Tk script includes some code (involving the 'argv0' variable) to determine the location of the shell script by extracting the name of the directory in which the Tk script lies.
#!/bin/sh ## ## SCRIPT NAME: ffmpeg_webcamAndAudio_MovieCapture.sh ## ##+####### ## PURPOSE: ## This script runs the 'ffmpeg' command after being provided with ## about 14 'ffmpeg' parameters passed to this script. ## ## This shell script is meant to be issued from the Tk GUI 'wrapper' ## script --- 'webcamAndAudio_MovieCapture_ffmpeg_FrontEnd.tk'. ## That Tk script is to get parameters for the 'ffmpeg' command --- ## for the purpose of recording the webcam and audio from a computer ## into a movie file. ## ## The 'ffmpeg' parameters are passed into this script via *positional* ## parameters in the order indicated below. ## ## Having the 'ffmpeg' call in a shell script instead of embedded in the ## Tk script facilitates testing and debugging. For example, this ## script can be tested independently of the Tk script. ('ffmpeg' ## is very sensitive to the order of the input parameters, as well ## as sensitive to the container-video-audio formats selected --- ## as evidenced by the many appeals for help on internet forums.) ## ##+###### ## INPUTS: ## ## Here are example default parameters for 'ffmpeg' from the Tk script, ## preceded by the variable names used in the Tk script: ## ## Var01: VIDEOsize "800x600" ## Var02: VIDEOsource "/dev/video0" ## Var03: VIDEOformat "video4linux2" ## Var04: VIDEOrate "25" ## Var05: VIDEOcodec "libx264" ## Var06: VIDEOotherParms "-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset" ## Var07: AUDIOformat "alsa" ## Var08: AUDIOinterface "pulse" ## Var09: AUDIOchannels "1" ## Var10: AUDIOcodec "pcm_s16le" ## Var11: AUDIOotherParms "-ar 22050 -ab 96k" ## Var12: Nthreads "1" ## Var13: CONTAINERformat "matroska" ## Var14: ENTRYfilename "$outDIR/$env(USER)_webcam_capture_movie.mkv" ## ## In this script, we will put those parameters in shell script variables ## using the same variable names as above --- except that we will ## use 'OUTfile' instead of 'ENTRYfilename' and 'CONTAINfmt' instead of ## 'CONTAINERformat'. ## ##+######################################################################### ## REFERENCE: http://ubuntuforums.org/archive/index.php/t-1392026.html ## "HOWTO: Proper Screencasting on Linux" (as seen in 2011) ## ## "...we capture audio from pulse (pulseaudio sound server) and encode it ## to *'lossless'* raw PCM with 2 audio channels (stereo). Then, we grab a ## video stream from x11 at a frame rate of 30 and a size of 1024×768 ## from the display :0.0 and encode it to *'lossless'* h264 using libx264. ## ... The resulting streams will be muxed in a Matroska container (.mkv)." ##+######################################################################### ## MAINTENANCE HISTORY: ## Started by: Blaise Montandon 2014jun02 Started based on the shell script ## 'ffmpeg_monitorAndAudio_MovieCapture.sh'. ## Updated by: Blaise Montandon 2014 ##+######################################################################### ## FOR TESTING: (to show statements as they execute) # set -x VIDEOsize="$1" VIDEOsource="$2" VIDEOformat="$3" VIDEOrate="$4" VIDEOcodec="$5" VIDEOotherParms="$6" AUDIOformat="$7" AUDIOinterface="$8" AUDIOchannels="$9" AUDIOcodec="$10" AUDIOotherParms="$11" Nthreads="$12" CONTAINfmt="$13" OUTfile="$14" ## FOR TESTING of this script without the Tk wrapper: ## (For stand-alone testing, change 'if test 1 = 0' to 'if test 1 = 1'.) if test 1 = 0 then VIDEOsize="800x600" # VIDEOsize="1024x768" # VIDEOsource="/dev/video1" VIDEOsource="/dev/video0" VIDEOformat="video4linux2" # VIDEOformat="video4linux" VIDEOrate="25" # VIDEOrate="30" VIDEOcodec="libx264" # VIDEOcodec="mpeg4" # VIDEOcodec="mpeg2video" # VIDEOcodec="mpeg1video" # VIDEOcodec="flv" # VIDEOcodec="libvpx" # VIDEOcodec="xvid" VIDEOotherParms="-vpre /usr/share/ffmpeg/libx264-lossless_ultrafast.ffpreset" # VIDEOotherParms="" AUDIOformat="alsa" # AUDIOformat="oss" AUDIOinterface="pulse" # AUDIOinterface="hw:2,0" # AUDIOinterface="/dev/dsp" AUDIOchannels="1" # AUDIOchannels="2" AUDIOcodec="pcm_s16le" # AUDIOcodec="libmp3lame" # AUDIOcodec="libfaac" # AUDIOcodec "vorbis" AUDIOotherParms="-ar 22050 -ab 96k" # AUDIOotherParms="-ar 44100 -ab 128k" Nthreads="1" # Nthreads="2" # Nthreads="0" ## auto-detect, max CPUs (not advisable?) CONTAINfmt="matroska" # CONTAINfmt="mpeg4" # CONTAINfmt="mpeg" # CONTAINfmt="flv" # CONTAINfmt="avi" # CONTAINfmt="webm" OUTfile="/tmp/${USER}_webcam_capture_movie.mkv" fi ## FOR TESTING: # echo "OUTfile: $OUTfile" ## Simply exit if there is no output filename passed to this script. if test "$OUTfile" = "" then exit fi ##+########################################################## ## Prepare to use the filename to hold the movie. ## Make sure we start with a new (empty) output file. ##+########################################################## rm -f "$OUTfile" ##+####################################################### ## Call on the 'ffmpeg' command, which puts the movie ## in file "$OUTfile". ## ## We run ffmpeg in an 'xterm' so that we can see its messages ## and the user can stop the recording by opening the xterm ## window and typing 'q' in the window. ## ## We could move the 'xterm' call into the calling Tk script. ## ## We do not use '&' to run this process in the background, ## but the Tk script that calls this script issues the call ## as a background process, rather than foreground. ##+############################################################### ## If you have another webcam applicaton running, such as 'Cheese', ## you may get the following error: ## [video4linux2 @ 0x892f700]Cannot find a proper format. ## It apparently 'ties up' the specified device --- in this case, ## /dev/video0. ################################################################## ## If you specify the wrong input device, you may get the following ## error: ## [video4linux2 @ 0x9fd4700]Cannot open video device /dev/video1 : ## No such file or directory ## /dev/video1: I/O error occurred ################################################################## ## FOR TESTING: (to show statements as they execute) # set -x xterm -bg black -fg white -hold -geometry 90x48+100+100 -e ffmpeg \ -f $VIDEOformat -r $VIDEOrate -s $VIDEOsize -i $VIDEOsource \ -f $AUDIOformat -ac $AUDIOchannels -i $AUDIOinterface \ -vcodec $VIDEOcodec $VIDEOotherParms \ -acodec $AUDIOcodec $AUDIOotherParms \ -threads $Nthreads "$OUTfile" ## The following order of parameters (all video, then all audio) gave ## the puzzling error message: Unknown decoder 'libx264' ## ## (Puzzling because I knew that the 'libx264' coder was available, ## because another order of the parameters in a different script worked. ## This is proof that 'ffmpeg' can give VERY MISLEADING error messages.) ## ## ffmpeg -f $VIDEOformat -r $VIDEOrate -s $VIDEOsize \ ## -i $VIDEOsource -vcodec $VIDEOcodec $VIDEOotherParms \ ## -f $AUDIOformat -i $AUDIOinterface -ac $AUDIOchannels -acodec $AUDIOcodec \ ## -threads $Nthreads "$OUTfile" ## ## It appears that 'ffmpeg' parameters should be grouped such that ## ALL the 'input' parameters (video AND audio) are to be specified BEFORE ## the 'output' (in particular, codec) parameters.
INSTALLING THE SCRIPTS:
The Tk script and the shell script could be put in a sub-directory of the user's home directory, such as $HOME/apps/tkMovieCaptureFromWebCam.
Then the user can use their desktop system (such as Gnome or KDE) to set up the Tk script as an icon on the desktop.
Then, whenever the user wants to record a webcam session, the user can click on the icon to startup this 'front end' to the 'ffmpeg' command.
LINK TO A MOVIE CAPTURE EXAMPLE
Here is a link to a movie capture (from a webcam) that I did with this GUI. [L2 ]
It is a capture of a 640x480 resolution webcam into an 800x600 movie.
This movie file is actually an edited version of the original movie capture. I captured the original in a Matroska container format with the video recorded in H.264 format and the audio in PCM format.
I used a shell script that uses 'ffmpeg' to clip an input movie file --- to clip off the beginning and end of the original movie capture --- leaving a movie just 7 seconds long.
The shell script put the movie out in a different (more compact) format --- an 'mp4' container format with the video in H.264 format and the audio in AAC format.
SOME POSSIBLE ENHANCEMENTS
I have no major enhancements that I can think of for the Tk script at this time. However, in the future, I may find that I may want/need to change some default video or audio or 'other' parameters for some of the container formats.
And I may find that it is worthwhile implementing the WEBM format.
I also plan to work on at least one other 'front end' for 'ffmpeg' --- for example, for clipping, cropping, audio-extraction, audio-addition, and some other movie file editing functions.
IN CONCLUSION
As I have said on several other code-donation pages on this wiki ...
There's a lot to like about a utility that is 'free freedom' --- that is, no-cost and open-source so that you can modify/enhance/fix it without having to wait for someone else to do it for you (which may be never).
A BIG THANK YOU to Ousterhout for starting Tcl-Tk, and a BIG THANK YOU to the Tcl-Tk developers and maintainers who have kept the simply MAH-velous 'wish' interpreter going.
uniquename 2014jun30 - UPDATE - 'ffmpeg' or 'avconv'
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'.
treaki - 2014-07-18 10:11:20
hi, thanks for the grate program. I was looking for an alternate of cheese which dosnt work anymore and It is working just fine on my debian sid thinkpad :). unfortunatly the audio not synchrony to the video (asyncron) (the video is sometimes to slow and sometimes to fast) is there something i can do about it? Thanks