root/trunk/install/perl/record-v4l2.pl

リビジョン 83, 56.5 kB (コミッタ: sorshi, コミット時期: 16 年 前)

foltiaHD最初のリリース。
デジタル録画はFriio/Friio BS/CSのみに対応。
ivtvは1.0系使用になりました。

  • svn:executable 属性の設定値: *
Line 
1 #!/usr/bin/perl
2 # record-v4l2.pl created by James A. Pattie <james@pcxperience.com> 04/10/2003
3 # Copyright 2003-2004
4 # Purpose: to record from the specified channel for the specified amount
5 # of time to the video OutputDirectory under the channel-start time name as video.mpg.
6
7 #
8 # You can always get the latest version of this script at
9 # http://www.pcxperience.org/
10 #
11
12 # 20071016 Patched by DCC-JPL Japan / foltia project / http://www.dcc-jpl.com/soft/foltia/
13
14 # 20030425 - 1.4 - Added devfs support based upon patch submitted by
15 #                  Jonathan Kolb <jkolb-ivtv@greyshift.net>
16 # 20030426 - 1.5 - Imported the ptune.pl functionality
17 # 20030426 - 1.6 - moved -F -> -L, -F now lets you specify the frequency to tune to.
18 # 20030427 - 1.7 - renamed to record_ivtv.pl per Kevin's request.  Added -R option.
19 # 20030430 - 1.8 - fixing some comparisons that needed to be strings, etc.
20 # 20030504 - 1.9 - Migrating to Video::ivtv for video resolution support.
21 # 20030505 - 1.10- Replaced open w/ sysopen but it doesn't make a difference.
22 #                  Starting to replace the Standard code w/ Video::ivtv methods.
23 #                  Added the version numbers that I require to the use statements.
24 # 20030507 - 1.11- Migrated to using get/setFrequency from Video::ivtv 0.03.
25 # 20030510 - 1.12- Migrated to using get/setInput from Video::ivtv 0.04.  Moved to using
26 #                  the exported method names rather than Video::ivtv::method().
27 #                  Converted to using enumerateStandard().
28 #                  Fixed the condition where switching Video Standards will most likely
29 #                  not get the correct channel and so would switch back with channel = 0
30 #                  which is invalid.  In this case I store the previous frequency, do the
31 #                  channel change but signal to restore the previous frequency on cleanup.
32 #                  Converted to using enumerateInput().
33 # 20030512 - 1.13- Added initial support for setting the bitrate/bitrate_peak values.
34 # 20030513 - 1.14- Tweaked the bitrate values to be closer to real DVD bitrates.
35 #                  Added support for the .ivtvrc config file and User Profiles.
36 # 20030516 - 1.15- Updated to the OO interface that Video::ivtv 0.06 now requires.
37 #                  Cleaned up a lot of the global variables into a settings hash.
38 #                  Made the -S command add any config items you specified on the command line
39 #                  that were not in the Profile being updated.  This way you can add new items.
40 #                  Made the config file work from a mapping hash so that we can easily add/remove
41 #                  config items in the future.
42 # 20030518 - 1.16- Fixed a Frequency bug that happened when changing Video Standards and the
43 #                  Frequency came from a user specified Profile.
44 # 20030519 - 1.17- Adding the rest of the Codec related options to the config file / defaults.
45 #                  Switched to using Getopt::Long.  You can specify all config file options at
46 #                  least by a --long version and still by the original -X command option.
47 #                  Cleaned up the option parsing code to take advantage of the mappings hash.
48 # 20030520 - 1.18- Fixing the handling of the Profile command line option.
49 # 20030524 - 1.19- Cleaned up the output for -L/--list-freqtable.  Changed --list -> --list-freqtable.
50 #                  Added support to detect the v4l2 driver in use and disable the ivtv "enhancements"
51 #                  if driver != "ivtv".
52 #                  Renamed to record-v4l2.pl to reflect the ability of this program to record from any
53 #                  v4l2 device but with special support for the ivtv driver.
54 # 20030524 - 1.20- Improving the Ctrl-C handling (cleanup before dying).  It may take a second or two
55 #                  before the program exits, but it should exit after resetting anything it changed, unless
56 #                  you had specified not to reset the card.
57 #                  Allow layering of profiles by calling -P/--profile multiple times.  Each profile will
58 #                  be layered over the last.  You will not be able to create/update a profile if you
59 #                  specify more than one though.
60 #                  Fixed a bug that would cause a parameter from the profile to be set n times, where n was
61 #                  the number of characters in the mapping string that consisted of the single letter | and
62 #                  the long command option name.  Ex:  Channel has 'c|channel' so the Channel value was being
63 #                  set 9 times instead of just the first time if it was in the profile.
64 # 20030525 - 1.21- Fixed devfsd detection code as it was overriding what came from the config file.
65 #                  Adding --no-record option so that we can start to implement the replacement functionality for
66 #                  ptune.pl (ie.  Set all values and then exit, do not reset the card and do not capture)
67 # 20030607 - 1.22- Adding --directory-format and --date-format options so that the user can specify the
68 #                  naming convention to use when specifying the directory the output file should be put in.
69 #                  Tweaked some of the defaults.
70 #                  Create the config file if it doesn't exist, regardless of the --save flag being specified.
71 #                  Added method error() to output an error condition that doesn't warrant the whole usage and
72 #                  converted all relevant usage() calls to error() calls.
73 #                  Added option --debug to dynamically on the fly enable debug output.
74 # 20030609 - 1.23- Added option --list-channels to display the currently selected frequency tables contents.
75 #                  Changed the default output directory to '.'.
76 #                  Moved $debug -> $settings{Debug} so it can be stored in the config file.  This allows you to
77 #                  turn debugging on for only certain profiles, etc.
78 #                  Restructured some of the validity tests to only happen as long as we are recording since they
79 #                  do not need to be validated when we are not recording.  Mainly to do with the output stuff.
80 # 20030610 - 1.24- Moved the tunerNum variable into the config file: TunerNum
81 #                  Added --tuner-num option to dynamically set it.
82 # 20030614 - 1.25- I now require Video::ivtv 0.09 to make sure everyone is using the version that fixes the known
83 #                  reported segfault issues.
84 #                  Added freqtable "custom" support so that people using the new feature in ptune-ui.pl and have
85 #                  set their default frequency table to be "custom" will just work when they specify channel X, etc.
86 #                  I'm now sorting the command line input since otherwise I can't guarantee the order options get
87 #                  processed in, but even that is wrong.  I need to use Tie::IxHash, but that isn't standard.
88 # 20030626 - 1.26- Updated to cover the audio -> audio_bitmask changes that Video::ivtv 0.11 implemented to cover
89 #                  the ivtv_ioctl_codec structure changes.
90 #                  Implemented config file versioning so that I know when the Audio entry needs to be updated in case it
91 #                  comes back in a future version of the ivtv_ioctl_codec structure.
92 # 20030628 - 1.27- Adding --list-inputs and --list-standards to display the available inputs and video standards.
93 # 20030713 - 1.28- Added code to make sure the codec properties are proper when switching standard to PAL/SECAM.
94 #                  Added config options SetMSPMatrix, MSPInput, MSPOutput, MSPSleep to allow the user to specify if they
95 #                  want the msp matrix updated any time the Video Standard is changed and to specify what they want programmed.
96 #                  Bumping the config file version to 2 to account for the new options.
97 # 20030715 - 1.29- Adding the missing msp matrix reset code in the reset section.
98 #                  Adding codec checks to make sure that they are right for NTSC.
99 #                  Made it legal to specify the channel by itself without -c/--channel.
100 # 20030822 - 1.30- Adding the missing codec value BitrateMode
101 # 20030927 - 1.31- Adding support to export the settings used as a shell or perl snippet for inclusion
102 #                  by scripts working with the recorded video files.
103 #                  Changing the default value of StreamType to 14 since that is near DVD quality.
104 # 20040306 - 1.32- Creating the parent directory if it doesn't exist.
105 #                  Making sure to update the InputName if the config specified a number so that input switching works 100%.
106 #                  Command line arguments now take precedence over Profile values, should have been this way always. :(
107 # 20040613 - 1.33- Removing the MSPMatrix related options and code.
108 #                  Adding a check for the 0.1.10 driver and not using the GOP_END ioctl if it is not that version.
109 #                  Brought it upto speed in regards to the 0.2.00rc1g driver - all known issues are now fixed.
110 #                  Added code to determine the version of the ivtv driver being used (0.1.10, 0.2.0, etc.) and
111 #                  output it in the video.settings file so we know what driver the capture was done with.
112
113
114 use strict;
115 use Getopt::Long qw(:config no_ignore_case bundling);
116 use Fcntl;
117 use Video::Frequencies 0.03;
118 use Video::ivtv 0.13;
119 use Config::IniFiles;
120
121 my $version="1.33";
122 my $cfgVersion = "3";
123 my $cfgVersionStr = "_configVersion_"# hopefully unique [defaults] value to let me know what version the config file is.
124 my $ivtvVersion = 0;  # used to store the detected version of the driver.  Needed for the CaptureLastGOP feature.
125
126 my @capabilities = ();  # The cards capabilities
127
128 my %settings = (
129   Channel           => 4,               # default to the ivtv default channel
130   RecordDuration    => 3595,            # default to 59 minutes 55 seconds (in seconds) - This lets 2 back to back cron jobs work!
131   InputNum          => 0,      # TV-Tuner 1
132   InputName         => "Tuner 1",
133   OutputDirectory   => ".",
134   VideoDevice       => "/dev/video0",
135   VideoWidth        => "720",   # 720x480-fullscreen NTSC
136   VideoHeight       => "480",
137   VideoStandard     => "NTSC-M", # L135 v060406.pl MMM "NTSC",  # NTSC, PAL or SECAM
138   VideoType         => "mpeg"# mpeg, yuv
139   BitrateMode       => 0,       # 0 = VBR, 1 = CBR
140   Bitrate           => "6500000",
141   PeakBitrate       => "8000000"# peak bitrate
142   Aspect            => 2,
143   AudioBitmask      => 0x00e9,
144   BFrames           => 3,
145   DNRMode           => 0,
146   DNRSpatial        => 0,
147   DNRTemporal       => 0,
148   DNRType           => 0,
149   Framerate         => 0,
150   FramesPerGOP      => 15,
151   GOPClosure        => 1,
152   Pulldown          => 0,
153   StreamType        => 14,  # 0 = PS, 1 = TS, 2 = MPEG1, 3 = PES_AV, 5 = PES_V, 7 = PES_A, 10 = DVD, 11 = VCD, 12 = SVCD, 13 = DVD-Special 1, 14 = DVD-Special 2
154   OutputFileName    => "video.mpg",
155   FrequencyTable    => "ntsc-cable"# default to NTSC_CABLE mapping.
156   Frequency         => "", # user specified frequency.
157   ResetCardSettings => 1,
158   ConfigFileName    => "$ENV{HOME}/.ivtvrc",
159   UpdateConfigFile  => 0,
160   UseConfigFile     => 0,
161   UsingIvtvDriver   => 1,  # default to being able to use the ivtv "enhancements".
162   DontRecord        => 0,  # default to always recording data.
163   DirectoryFormatString => "%I-%c-%d", # format string used to define the sub directory under OutputDirectory
164   DateTimeFormatString  => "+%Y%m%d-%H%M", # format string used to represent the date/time if the user wants it in their DirectoryFormatString
165   # define the Codec related min/max values
166   minBitrate        => 1,
167   maxBitrate        => 14500000,
168   minPeakBitrate    => 1150,
169   maxPeakBitrate    => 16000000,
170   # output settings file settings
171   OutputSettings     => 1, # bool 0 or 1
172   OutputSettingsName => "video.settings",
173   OutputSettingsType => "shell", # shell or perl
174   # other settings
175   CaptureLastGOP    => 1,  # default to trying to Capture the Last GOP of the encoder stream.
176   Debug             => 0,
177   TunerNum          => 1,
178   v4l2DriverVersion => 0,
179   v4l2DriverVersionStr => "",
180   v4l2Driver        => "",
181 );
182
183 my $result="";
184 my @profileNames=(); # list of user defined sections to work with in the config file.
185 my %profileOverloads = ();  # hash of entries the Profiles overloaded so InputName <-> InputNum works properly.
186 my %configIni;      # config hash we tie to for Config::IniFiles.
187 my $ivtvObj = Video::ivtv->new();
188
189 # map the Settings/Config file parameter to the command line variable that specifies it.
190 my %mappings = (
191     "Channel"           => "c|channel",
192     "RecordDuration"    => "t|duration",
193     "InputNum"          => "i|inputnum",
194     "InputName"         => "I|inputname",
195     "OutputDirectory"   => "D|directory",
196     "VideoDevice"       => "d|input",
197     "VideoWidth"        => "W|width",
198     "VideoHeight"       => "H|height",
199     "VideoStandard"     => "s|standard",
200     "VideoType"         => "T|type",
201     "BitrateMode"       => "bitrate-mode",
202     "Bitrate"           => "b|bitrate",
203     "PeakBitrate"       => "B|peakbitrate",
204     "Aspect"            => "aspect",
205     "AudioBitmask"      => "audio-bitmask",
206     "BFrames"           => "bframes",
207     "DNRMode"           => "dnrmode",
208     "DNRSpatial"        => "dnrspatial",
209     "DNRTemporal"       => "dnrtemporal",
210     "DNRType"           => "dnrtype",
211     "Framerate"         => "framerate",
212     "FramesPerGOP"      => "framespergop",
213     "GOPClosure"        => "gopclosure",
214     "Pulldown"          => "pulldown",
215     "StreamType"        => "streamtype",
216     "OutputFileName"    => "o|output",
217     "FrequencyTable"    => "f|freqtable",
218     "Frequency"         => "F|frequency",
219     "ResetCardSettings" => "R|noreset",
220     "DirectoryFormatString" => "directory-format",
221     "DateTimeFormatString"  => "date-format",
222     "Debug"             => "debug",
223     "TunerNum"          => "tuner-num",
224     "OutputSettings"     => "output-settings",
225     "OutputSettingsName" => "output-settings-name",
226     "OutputSettingsType" => "output-settings-type",
227     "CaptureLastGOP"    => "capture-last-gop",
228   );
229
230 my %codecMappings = (
231     "Aspect"       => "aspect",
232     "AudioBitmask" => "audio_bitmask",
233     "BFrames"      => "bframes",
234     "BitrateMode"  => "bitrate_mode",
235     "Bitrate"      => "bitrate",
236     "PeakBitrate"  => "bitrate_peak",
237     "DNRMode"      => "dnr_mode",
238     "DNRSpatial"   => "dnr_spatial",
239     "DNRTemporal"  => "dnr_temporal",
240     "DNRType"      => "dnr_type",
241     "Framerate"    => "framerate",
242     "FramesPerGOP" => "framespergop",
243     "GOPClosure"   => "gop_closure",
244     "Pulldown"     => "pulldown",
245     "StreamType"   => "stream_type",
246   );
247
248 # check for devfs support
249 if ( -e "/dev/.devfsd" )
250 {
251   $settings{VideoDevice} = "/dev/v4l/video0";
252 }
253
254 # check for the config file
255 if (-f $settings{ConfigFileName})
256 {
257   $settings{UseConfigFile} = 1;
258
259   # tie to it.
260   tie %configIni, 'Config::IniFiles', (-file => $settings{ConfigFileName}) or die "Error: Opening config file '$settings{ConfigFileName}' failed! $!\n";
261
262   my $profile = "defaults";
263   if (exists $configIni{$profile})
264   {
265     my $saveFile = 0;
266     # check version of the config file.
267     if (!exists $configIni{$profile}{$cfgVersionStr})
268     {
269       print "Updating config file to version 1...\n";
270
271       # first version config file!  Update the Audio -> AudioBitmask entries.
272       $configIni{$profile}{$cfgVersionStr} = 1;
273
274       # find all entries that have Audio and move to AudioBitmask.
275       foreach my $p (keys %configIni)
276       {
277         if (exists $configIni{$p}{Audio})
278         {
279           $configIni{$p}{AudioBitmask} = $configIni{$p}{Audio};
280           delete $configIni{$p}{Audio};
281         }
282       }
283      
284       $saveFile = 1;  # signal we need to save the config changes.
285     }
286     if ($configIni{$profile}{$cfgVersionStr} != $cfgVersion)
287     {
288       # we need to upgrade
289       if ($configIni{$profile}{$cfgVersionStr} == 1)
290       {
291         print "Updating config file to version 2...\n";
292         # add the MSP Matrix related options.
293         $configIni{$profile}{SetMSPMatrix} = $settings{SetMSPMatrix};
294         $configIni{$profile}{MSPInput} = $settings{MSPInput};
295         $configIni{$profile}{MSPOutput} = $settings{MSPOutput};
296         $configIni{$profile}{MSPSleep} = $settings{MSPSleep};
297         $configIni{$profile}{$cfgVersionStr} = 2;
298         $saveFile = 1;
299       }
300       if ($configIni{$profile}{$cfgVersionStr} == 2)
301       {
302         print "Updating config file to version 3...\n";
303         # remove the MSP Matrix related options from all profiles.
304         foreach my $p (keys %configIni)
305         {
306           foreach my $k (qw(SetMSPMatrix MSPInput MSPOutput MSPSleep))
307           {
308             if (exists $configIni{$p}{$k})
309             {
310               delete $configIni{$p}{$k};
311             }
312           }
313         }
314         $configIni{$profile}{CaptureLastGOP} = 1;
315         $configIni{$profile}{$cfgVersionStr} = 3;
316         $saveFile = 1;
317       }
318     }
319
320     if ($saveFile)
321     {
322       # now save the updated config file before we continue.
323       tied(%configIni)->RewriteConfig or die "Error: Writing config file '$settings{ConfigFileName}' failed!  $!\n";
324     }
325
326     # update the defaults stored.
327     foreach my $arg (keys %mappings)
328     {
329       if (exists $configIni{$profile}{$arg})
330       {
331         $settings{$arg} = $configIni{$profile}{$arg};
332         #print "settings{$arg} = '" . $settings{$arg} . "'\n";
333       }
334     }
335   }
336   else
337   {
338     print "Warning: config file '$settings{ConfigFileName}' exists but does not have the\n[$profile] section!  Use -S to create it without specifying -P.\n\n";
339   }
340 }
341 else  # create the config file
342 {
343   print "Auto Creating config file $settings{ConfigFileName}...\n";
344   my $profile = "defaults";
345
346   # we have to create the config file and tie to it.
347   tie %configIni, 'Config::IniFiles', () or die "Error: Initializing config file '$settings{ConfigFileName}' failed! $!\n";
348
349   # now set the name to work with.
350   tied(%configIni)->SetFileName($settings{ConfigFileName}) or die "Error: Setting config file to '$settings{ConfigFileName}' failed! $!\n";
351
352   $configIni{$profile} = {};  # make sure the section exists.
353
354   foreach my $arg (keys %mappings)
355   {
356     $configIni{$profile}{$arg} = $settings{$arg};
357     print "configIni{$profile}{$arg} = '" . $settings{$arg} . "'\n" if $settings{Debug};
358   }
359
360   # set the config file version
361   $configIni{$profile}{$cfgVersionStr} = $cfgVersion;
362
363   # write the config file out.
364   tied(%configIni)->RewriteConfig or die "Error: Writing config file '$settings{ConfigFileName}' failed!  $!\n";
365 }
366
367 # build up the "custom" frequency table
368 my %customMap = ();
369 foreach my $profileName (keys %configIni)
370 {
371   next if $profileName =~ /^(defaults)$/;
372
373   if (exists $configIni{$profileName}{Frequency})
374   {
375     $customMap{$profileName} = $configIni{$profileName}{Frequency};
376   }
377 }
378 $CHANLIST{custom} = \%customMap;
379
380 # enumerations
381 my @standards;
382 my %name2std;
383 my @inputs;
384 my %name2input;
385 my @codecInfo;        # stores the Codec Info
386 my @newCodecInfo;     # the version we mess with.
387 # Current settings (Input, Channel, Standard)
388 my $curinput;
389 my $curinputName;
390 my $std;
391 my $curstd = "???";
392 my $curStandard = 0;  # numeric representation.
393 my $curChannel = 0;
394 my $curFrequency = 0;
395
396 my $tuner;
397 my $settingsFH;  # File Handle for output settings.
398 my $err;
399 my $v4l2input;
400
401 my $tmpDirectoryStr = formatDirectoryString();
402 my $versionStr = "record-v4l2.pl $version for use with http://ivtv.sf.net/";
403 my $usageStr = <<"END_OF_USAGE";
404 $versionStr
405
406 Usage: record-v4l2.pl [--channel CHANNEL] [--duration TIME]
407        [--directory DIRECTORY] [--output OUTPUT]
408        [--directory-format FORMAT] [--date-format FORMAT]
409        [--input VIDEO_DEV][--width WIDTH --height HEIGHT]
410        [--standard STANDARD] [--type TYPE]
411        [--inputnum INPUT#] [--inputname INPUT NAME]
412        [--freqtable FREQENCY MAP] [--frequency FREQUENCY]
413        [--bitrate-mode MODE]
414        [--bitrate BITRATE] [--peakbitrate PEAK_BITRATE]
415        [--profile PROFILE] [--list-freqtable] [--list-channels]
416        [--no-record] [--noreset] [--save] [--help] [--version]
417        [--aspect ASPECT] [--audio-bitmask AUDIO-BITMASK] [--bframes BFRAMES]
418        [--dnrmode DNRMODE] [--dnrspatial DNRSPATIAL]
419        [--dnrtemporal DNRTEMPORAL] [--dnrtype DNRTYPE]
420        [--framerate FRAMERATE] [--framespergop FRAMESPERGOP]
421        [--gopclosure GOPCLOSURE] [--capture-last-gop GOP_END]
422        [--pulldown PULLDOWN] [--streamtype STREAMTYPE] [--debug]
423        [--tuner-num TUNERNUM] [--output-settings BOOL]
424        [--output-settings-name FNAME] [--output-settings-type TYPE]
425        [--list-inputs] [--list-standards] [CHANNEL]
426
427   -c/--channel CHANNEL: channel number to switch to
428       NOTE: You can also specify the channel by itself.
429             Ex.  record-v4l2.pl 73
430             would change to channel 73 using the default settings
431             or the settings from your ~/.ivtvrc config file.
432   -t/--duration TIME: number of seconds to record
433   -D/--directory DIRECTORY: Base directory to record into
434   --directory-format FORMAT: format string that specifies the
435        sub-directory to create under the base directory that
436        the output file will be created in.  This can be empty
437        to indicate no sub-directory should be created.
438
439        Available tokens are:
440          %d - date formatted by --date-format
441          %I - input name recorded from
442               Any white space in the name is converted to
443               underscores (_).  Ex. 'Tuner 0' => 'Tuner_0'
444
445          %c - channel or "freq-#" frequency
446
447   --date-format FORMAT: format string that specifies the
448        date format string to generate and substitute for
449        %d in the --directory-format string.
450
451        Available tokens:  see the date commands man page.
452          The string must start with a + (plus).
453
454   -o/--output OUTPUT: name of file to create
455   -d/--input VIDEO_DEV: video device to capture from
456   -W/--width WIDTH: width of screen (720 for NTSC fullscreen)
457   -H/--height HEIGHT: height of screen (480 for NTSC fullscreen)
458   -s/--standard STANDARD: NTSC, PAL or SECAM - video standard to record in
459   -T/--type TYPE: mpeg or yuv output
460   -i/--inputnum INPUT#:
461        The index number of the input you want to use (0 -> n-1)
462   -I/--inputname INPUT NAME: The name of the input you want to use.
463   -f/--freqtable FREQUENCY MAP: Specify the frequency mapping to use.
464   -F/--frequency FREQUENCY: Specify the frequency to tune to.
465                 ex. 517250 = NTSC Cable 73 (SCiFi)
466   --tuner-num TUNERNUM: Specify the tuner to use.
467   -L/--list-freqtable:
468        list all available frequency mappings that Video::Frequencies knows
469   --list-channels: lists all channels and their frequencies for the
470        specified frequency table being used.
471   --list-inputs: lists all inputs the v4l2 driver reports.
472   --list-standards: lists all Video Standards the v4l2 driver supports.
473   -R/--noreset: Do not Reset anything that was changed
474       (standard, channel, resolution, etc.)
475   --no-record: Do not create any directories, capture data or reset the card
476               back to original settings.  This is the ptune.pl mode.
477   -h/--help: display this help
478   -v/--version: display the version of this program
479   --debug: turns on debug output
480   --output-settings BOOL: Turns on or off the creation of the settings
481                           file that contains perl or shell variables that
482                           represent the settings used to record the video file.
483                           This feature is ignored if --no-record specified.
484   --output-settings-name FNAME: The name of the file to write the settings to.
485                                 It must end in .settings.
486   --output-settings-type TYPE: Either 'shell' or 'perl'.
487             If 'shell', then all variables output are prefixed with REC_
488             and are upper cased.  Ex: StreamType => REC_STREAMTYPE="14"
489             If 'perl', then all variables output are created in the
490             %settings hash.  Ex: StreamType => $settings{StreamType} = "14";
491
492   Codec related options:
493   --bitrate-mode MODE: 0 = VBR, 1 = CBR
494   -b/--bitrate BITRATE: Specify the Bitrate to capture at in Mbps
495   -B/--peakbitrate PEAK_BITRATE: Specify the Peak Bitrate to capture at in Mbps
496   --aspect ASPECT: Specify the aspect ratio
497   --audio-bitmask AUDIO-BITMASK:  Specify the audio bitmask value
498   --bframes BFRAMES: Specify the number of B frames value
499   --dnrmode DNRMODE: Specify the dnr_mode value
500   --dnrspatial DNRSPATIAL: Specify the dnr_spatial value
501   --dnrtemporal DNRTEMPORAL: Specify the dnr_temporal value
502   --dnrtype DNRTYPE: Specify the dnr_type value
503   --framerate FRAMERATE: Specify the framerate value. 0 = 30fps, 1 = 25fps
504   --framespergop FRAMESPERGOP: Specify the GOP size
505   --gopclosure GOPCLOSURE: Specify if you want open/closed GOP's.
506   --capture-last-gop GOP_END: Specify if you want the encoder stream to try and
507     capture the last GOP, thus generating a 100% valid mpeg2 file.
508     1 = yes (default), 0 = no.
509   --pulldown PULLDOWN: 1 = Inverse telecine on, 0 = off
510   --streamtype STREAMTYPE: Specify the stream_type value
511       Valid Values are:
512         0 - PS
513         1 - TS
514         2 - MPEG1
515         3 - PES_AV
516         5 - PES_V
517         7 - PES_A
518        10 - DVD
519        11 - VCD
520        12 - SVCD
521        13 - DVD-Special 1
522        14 - DVD-Special 2
523
524   Config file related options:
525   -P/--profile PROFILE: Override defaults and command line values with the
526               config entries in the section labeled [PROFILE] from the
527               config file $settings{ConfigFileName}.
528               Examples: -P NTSC-DVD, -P PAL-DVD, --profile MY-SETTINGS
529
530               You can specify this option multiple times and each successive
531               profile will overlay the defaults and any previous profiles.
532               You will not be able to create/update a profile if you do
533               specify multiple profiles.
534   -S/--save: save the current values as the defaults in
535       $settings{ConfigFileName}.
536       If -P/--profile PROFILE is specified, then those values that exist in
537       the specified profile will be updated.  If the profile doesn't exist,
538       then it will be created, but will have all possible config items
539       defined in it.  It will be your responsibility to hand check the
540       config file and remove any config items you do not want set for
541       that profile.
542       Any options specified on the command line will override options
543       defined in the config file.
544
545 Notes:
546   If you specify both -i/--inputnum and -I/--inputname then
547       -i/--inputnum will take precedence.
548
549   If you specify both -c/--channel and -F/--frequency then
550       -F/--frequency will take precedence.
551
552   If you use a Profile, it has the ability to override all command line
553     arguments, so check your Profile first if things seem to be ignored.
554
555 Defaults:
556  --duration $settings{RecordDuration} --input $settings{VideoDevice} --width $settings{VideoWidth} --height $settings{VideoHeight} --standard $settings{VideoStandard}
557  --type $settings{VideoType} --directory $settings{OutputDirectory} --output $settings{OutputFileName}
558  --directory-format "$settings{DirectoryFormatString}" --date-format "$settings{DateTimeFormatString}"
559  --inputnum $settings{InputNum} --inputname '$settings{InputName}' --freqtable $settings{FrequencyTable} --capture-last-gop $settings{CaptureLastGOP}
560  --bitrate $settings{Bitrate} --peakbitrate $settings{PeakBitrate} --aspect $settings{Aspect} --audio-bitmask $settings{AudioBitmask} --bframes $settings{BFrames}
561  --dnrmode $settings{DNRMode} --dnrspatial $settings{DNRSpatial} --dnrtemporal $settings{DNRTemporal} --dnrtype $settings{DNRType}
562  --framerate $settings{Framerate} --framespergop $settings{FramesPerGOP} --gopclosure $settings{GOPClosure} --pulldown $settings{Pulldown} --streamtype $settings{StreamType}
563  --tuner-num $settings{TunerNum} --output-settings $settings{OutputSettings} --output-settings-name $settings{OutputSettingsName} --output-settings-type $settings{OutputSettingsType}
564
565  config file = '$settings{ConfigFileName}'
566
567  If Channel = $settings{Channel}, this would create:
568  $tmpDirectoryStr$settings{OutputFileName}
569
570  Note:  This script relies on Perl Modules: Video::Frequencies, Video::ivtv,
571  Config::IniFiles and Getopt::Long.
572 END_OF_USAGE
573
574 # handle user input here
575 my %opts;
576 #getopts('c:t:o:hd:W:H:s:T:D:vi:I:f:F:LRb:B:P:S', \%opts);
577 GetOptions(\%opts, "channel|c=s", "duration|t=i", "output|o=s", "help|h", "input|d=s", "width|W=i", "height|H=i", "standard|s=s",
578                    "type|T=s", "directory|D=s", "version|v", "inputnum|i=i", "inputname|I=s", "freqtable|f=s", "frequency|F=i", "list-freqtable|L",
579                    "noreset|R", "bitrate|b=i", "peakbitrate|B=i", "profile|P=s@", "save|S", "aspect=i", "audio-bitmask=s", "bframes=i", "dnrmode=i", "dnrspatial=i",
580                    "dnrtemporal=i", "dnrtype=i", "framerate=i", "framespergop=i", "gopclosure=i", "pulldown=i", "capture-last-gop=i",
581                    "streamtype=i", "no-record", "directory-format=s", "date-format=s", "debug", "list-channels",
582                    "tuner-num=i", "list-inputs", "list-standards", "bitrate-mode=i", "output-settings=i", "output-settings-name=s", "output-settings-type=s");
583 if (scalar keys %opts == 0 && @ARGV == 0)
584 {
585   usage(0, "");
586 }
587 foreach my $option (sort keys %opts)
588 {
589   my $found = 0;
590   foreach my $mapName (keys %mappings)
591   {
592     if ($option =~ /^($mappings{$mapName})$/)
593     {
594       $settings{$mapName} = $opts{$option};
595       $found = 1;
596       print "$mapName = '$opts{$option}'\n" if $settings{Debug};
597     }
598   }
599   if (!$found)
600   {
601     # handle the non-settings cases.
602     if ($option =~ /^(L|list-freqtable)$/)
603     {
604       my $errStr = "\nAvailable Frequency Mappings:\n";
605       foreach my $name (sort keys %CHANLIST)
606       {
607         $errStr .= "$name\n";
608       }
609       print "$versionStr\n$errStr";
610       exit 0;
611     }
612     elsif ($option eq "list-channels")
613     {
614       my $errStr = "\nAvailable Channels for $settings{FrequencyTable}:\n";
615       foreach my $name (sort { $a <=> $b } keys %{$CHANLIST{$settings{FrequencyTable}}})
616       {
617         $errStr .= "$name\t= $CHANLIST{$settings{FrequencyTable}}->{$name}\n";
618       }
619       print "$versionStr\n$errStr";
620       exit 0;
621     }
622     elsif ($option =~ /^(no-record)$/)
623     {
624       $settings{DontRecord} = 1;
625     }
626     elsif ($option =~ /^(S|save)$/)
627     {
628       $settings{UpdateConfigFile} = 1;
629     }
630     elsif ($option =~ /^(P|profile)$/)
631     {
632       @profileNames = @{$opts{$option}};
633     }
634     elsif ($option =~ /^(v|version)$/)
635     {
636       print "$versionStr\n";
637       exit 0;
638     }
639     elsif ($option =~ /^(h|help)$/)
640     {
641       usage(0, "");
642     }
643     elsif ($option =~ /^(list-inputs|list-standards)$/)
644     {
645       # do nothing for now since they will be handled later.
646     }
647     else
648     {
649       usage(1, "-$option is an unknown option!");
650     }
651   }
652 }
653
654 if (@profileNames)
655 {
656   # loop over all profiles the user specified.
657   foreach my $profileName (@profileNames)
658   {
659     print "profile = '$profileName'\n" if $settings{Debug};
660     # for now the profile can not be "defaults".
661     if ($profileName eq "defaults")
662     {
663       error(1, "Profile = '$profileName' is invalid!");
664     }
665     if (exists $configIni{$profileName})
666     {
667       # update defaults that exist in this profile as long as the entry wasn't specified on the command line.
668       my $profile = $profileName;
669
670       foreach my $arg (keys %mappings)
671       {
672         # handle the long/short command option versions
673         my $cmdSpecified = 0;
674         foreach my $option (split(/\|/, $mappings{$arg}))
675         {
676           if (exists $opts{$option})
677           {
678             $cmdSpecified = 1;
679             last;
680           }
681         }
682         #print "arg = '$arg', option = '$option'\n" if $settings{Debug};
683         if (exists $configIni{$profile}{$arg} && !$cmdSpecified)
684         {
685           $profileOverloads{$arg} = $settings{$arg};  # preserve the old value.
686           $settings{$arg} = $configIni{$profile}{$arg};
687           print "settings{$arg} = '" . $settings{$arg} . "'\n" if $settings{Debug};
688         }
689       }
690     }
691     else
692     {
693       if ($settings{UpdateConfigFile} && @profileNames == 1)
694       {
695         print "Warning:  Profile = '$profileName' will be created.\n" if ($settings{Debug});
696       }
697       else
698       {
699         error(1, "Profile = '$profileName' does not exist! You must specify -S/--save to create it.");
700       }
701     }
702   }
703 }
704
705 # verify input
706
707 if (@ARGV)
708 {
709   if (exists $opts{c} || exists $opts{channel})
710   {
711     print "Warning: ignoring channel argument and using '$ARGV[0]' instead.\n";
712   }
713   $settings{Channel} = $ARGV[0];
714 }
715
716 my $directoryName;
717 if (!$settings{DontRecord})
718 {
719   print "RecordDuration = $settings{RecordDuration}\n" if $settings{Debug};
720
721   if ($settings{VideoType} !~ /^(mpeg|yuv)$/)
722   {
723     error(1, "Video Type = '$settings{VideoType}' is invalid!");
724   }
725   if ($settings{VideoType} eq "yuv")
726   {
727     # see if we need to change our defaults.
728     if (!exists $opts{o} && !exists $opts{output})
729     {
730       $settings{OutputFileName} = "video.yuv";
731     }
732     if (!exists $opts{d} && !exists $opts{input})
733     {
734       if ( -e "/dev/.devfsd" )
735       {
736         $settings{VideoDevice} = "/dev/v4l/yuv0";
737       }
738       else
739       {
740         $settings{VideoDevice} = "/dev/yuv0";
741       }
742     }
743   }
744
745   if ( ! -d "$settings{OutputDirectory}")
746   {
747     $result = `mkdir -p $settings{OutputDirectory}`;
748   }
749   # make directory
750   $directoryName = formatDirectoryString();
751   $result=`mkdir -p $directoryName`;
752 }
753
754 # verify the output-settings options
755 if ($settings{OutputSettings} !~ /^[01]$/)
756 {
757   error(1, "OutputSettings = '$settings{OutputSettings}' is invalid!");
758 }
759 if ($settings{OutputSettings} && $settings{DontRecord})
760 {
761   $settings{OutputSettings} = 0;  # turn off feature since we are not recording.
762 }
763 if ($settings{OutputSettings})
764 {
765   if ($settings{OutputSettingsName} !~ /^(.+\.settings)$/)
766   {
767     error(1, "OutputSettingsName = '$settings{OutputSettingsName}' is invalid!  It must end in .settings.");
768   }
769   if ($settings{OutputSettingsType} !~ /^(shell|perl)$/)
770   {
771     error(1, "OutputSettingsType = '$settings{OutputSettingsType}' is invalid!  It must be either 'shell' or 'perl'.");
772   }
773   sysopen($settingsFH, "$directoryName/$settings{OutputSettingsName}", O_CREAT | O_WRONLY) or die "Error creating file '$settings{OutputSettingsName}': $!\n";
774   outputSettingSetup();
775 }
776
777 if ( ! -c "$settings{VideoDevice}")
778 {
779   error(1, "Video Dev = '$settings{VideoDevice}' is invalid!  $!");
780 }
781
782 # now that the video device has been semi validated, we can use it to lookup
783 # the inputs, standards, etc. and use that for validating some of the following
784 # pieces of user input.
785 sysopen($tuner, $settings{VideoDevice}, O_RDWR) or die "Error unable to open '$settings{VideoDevice}': $!";
786 my $tunerFD = fileno($tuner);
787
788 outputSetting("VideoDevice");
789
790 # get the current capabilities.
791 @capabilities = $ivtvObj->getCapabilities($tunerFD);
792 if (@capabilities != keys %{$ivtvObj->{capIndexes}})
793 {
794   error(1, "getCapabilities() failed!");
795 }
796 # calculate the driver version info.
797 my $driverVersionHex = sprintf("%08x", $capabilities[$ivtvObj->{capIndexes}{version}]);
798 $driverVersionHex =~ /^(\d{4})(\d{2})(\d{2})$/;
799 my $driverVersionMajor = int($1);
800 my $driverVersionMinor = int($2);
801 my $driverVersionPatch = int($3);
802 my $driverVersionStr = $driverVersionMajor . "." . $driverVersionMinor . "." . $driverVersionPatch;
803
804 $settings{v4l2DriverVersion} = $capabilities[$ivtvObj->{capIndexes}{version}];
805 $settings{v4l2DriverVersionStr} = $driverVersionStr;
806 $settings{v4l2Driver} = $capabilities[$ivtvObj->{capIndexes}{driver}];
807 outputSetting("v4l2Driver");
808 outputSetting("v4l2DriverVersion");
809 outputSetting("v4l2DriverVersionStr");
810
811 if ($settings{Debug})
812 {
813   print "V4l2 Capabilities:  driver='$capabilities[$ivtvObj->{capIndexes}{driver}]', version='$capabilities[$ivtvObj->{capIndexes}{version}]', '$driverVersionStr'\n";
814 }
815 if ($capabilities[$ivtvObj->{capIndexes}{driver}] ne "ivtv")
816 {
817   $settings{UsingIvtvDriver} = 0;  # we can't use the ivtv "enhancements".
818   print "Warning:  V4l2 driver = '$capabilities[$ivtvObj->{capIndexes}{driver}]' does not support the ivtv \"enhancements\"!\n";
819   print "          All codec and ivtv specific options will be ignored.\n\n";
820 }
821 elsif ($capabilities[$ivtvObj->{capIndexes}{version}] <= 265)
822 {
823   $settings{CaptureLastGOP} = 0;  # we can't use the ivtv GOP_END feature.
824   print "Warning:  ivtv driver is not new enough to use the GOP_END feature!\n";
825 }
826 $ivtvVersion = $capabilities[$ivtvObj->{capIndexes}{version}];
827
828 my $i;
829
830 # get the current video standard
831 $std = $ivtvObj->getStandard($tunerFD);
832 if ($std > 0)
833 {
834   printf("Standard: 0x%08x\n",$std) if ($settings{Debug});
835 }
836 else
837 {
838   die "Error: getStandard() failed!\n";
839 }
840
841 # get the current input
842 $curinput = $ivtvObj->getInput($tunerFD);
843 if ($curinput < 0)
844 {
845   die "Error: getInput() failed!\n";
846 }
847 printf("Input: 0x%08x\n",$curinput) if ($settings{Debug});
848
849 # flags to indicate when we should stop reading from the card.
850 my $done=0;
851 my $stopGOP=0;   # indicates if we are asking for the Last GOP
852 my $endStream=0; # indicates if we are in the final read state.
853 # Standards
854 for ($i=0; !$done; ++$i)
855 {
856   my($index,$std_id,$name,$frameperiod_n,$frameperiod_d,$framelines) = $ivtvObj->enumerateStandard($tunerFD, $i);
857   if ($index == -1)
858   {
859     $done = 1;
860   }
861   else
862   {
863     printf("%d 0x%08x %s %d/%d %d\n",$index,$std_id,$name,$frameperiod_n,$frameperiod_d,$framelines) if ($settings{Debug});
864     push @standards, [($name,$std_id)];
865     $name2std{$name} = $std_id;
866     if( (($std_id & $std) == $std))
867     {
868       $curstd = $name;
869       $curStandard = $std;
870     }
871   }
872 }
873
874 if (exists $opts{'list-standards'})
875 {
876   print "$versionStr\n";
877   print "Available Video Standards:\n";
878   foreach my $standard (@standards)
879   {
880     print "$standard->[0]\n";
881   }
882   exit 0;
883 }
884
885 $done=0;
886 # Inputs
887 for ($i=0; !$done; ++$i)
888 {
889   my($index,$name,$type,$audioset,$tuner,$std,$status) = $ivtvObj->enumerateInput($tunerFD, $i);
890   if ($index == -1)
891   {
892     $done = 1;
893   }
894   else
895   {
896     push @inputs, $name;
897     $name2input{$name} = $index;
898   }
899 }
900 $curinputName = $inputs[$curinput];
901
902 if (exists $opts{'list-inputs'})
903 {
904   print "$versionStr\n";
905   print "Available Inputs:\n";
906   my $counter = 0;
907   foreach my $input (@inputs)
908   {
909     print "$counter: $input\n";
910     $counter++;
911   }
912   exit 0;
913 }
914
915 if ($settings{UsingIvtvDriver})
916 {
917   # get the current Codec Info
918   @codecInfo = $ivtvObj->getCodecInfo($tunerFD);
919   if (@codecInfo != keys %{$ivtvObj->{codecIndexes}})
920   {
921     error(1, "getCodecInfo() failed!");
922   }
923   @newCodecInfo = $ivtvObj->getCodecInfo($tunerFD);
924   if (@newCodecInfo != keys %{$ivtvObj->{codecIndexes}})
925   {
926     error(1, "getCodecInfo() failed!");
927   }
928 }
929
930 # finish validating the user input.
931
932 if (!$settings{DontRecord})
933 {
934   if ($settings{RecordDuration} !~ /^(\d+)$/)
935   {
936     error(1, "Time = '$settings{RecordDuration}' is invalid!");
937   }
938
939   outputSetting("RecordDuration");
940   outputSetting("OutputDirectory");
941
942   # assume for now we are only generating mpeg files.
943 #  if (($settings{VideoType} eq "mpeg" && $settings{OutputFileName} !~ /^.+\.mpg$/) || ($settings{VideoType} eq "yuv" && $settings{OutputFileName} !~ /^.+\.yuv$/))
944 #  {
945 #    error(1, "Output = '$settings{OutputFileName}' is invalid!");
946 #  }
947
948   outputSetting("VideoType");
949   outputSetting("OutputFileName");
950
951   if ($settings{DateTimeFormatString} !~ /^(\+((\%.)|.)+)$/)
952   {
953     usage(1, "Date Format String = '$settings{DateTimeFormatString}' is invalid!");
954   }
955
956   outputSetting("DateTimeFormatString");
957 }
958
959 if ($settings{VideoWidth} !~ /^(\d+)$/)
960 {
961   error(1, "Width = '$settings{VideoWidth}' is invalid!");
962 }
963
964 outputSetting("VideoWidth");
965
966 if ($settings{VideoHeight} !~ /^(\d+)$/)
967 {
968   error(1, "Height = '$settings{VideoHeight}' is invalid!");
969 }
970
971 outputSetting("VideoHeight");
972
973 if (!exists $name2std{$settings{VideoStandard}})
974 {
975   my $validStandards = join(", ", keys(%name2std));
976   error(1, "Video Standard = '$settings{VideoStandard}' is invalid!\nValid Standards are: $validStandards");
977 }
978
979 outputSetting("VideoStandard");
980
981 if (exists $opts{i} || exists $opts{inputnum} || ($settings{InputNum} != $name2input{$settings{InputName}} && exists $profileOverloads{InputNum}))
982 {
983   if ($settings{InputNum} < 0 || $settings{InputNum} >= scalar(@inputs))
984   {
985     error(1, "Video Input = '$settings{InputNum}' is invalid!\nValid Inputs are from 0 - " . int(scalar(@inputs) - 1));
986   }
987   $settings{InputName} = $inputs[$settings{InputNum}];
988 }
989
990 if ((exists $opts{I} || exists $opts{inputname} || $settings{InputNum} != $name2input{$settings{InputName}}) && !(exists $opts{i} || exists $opts{inputnum}))
991 {
992   if (!exists $name2input{$settings{InputName}})
993   {
994     my $validInputs = join(", ", @inputs);
995     error(1, "Video Input Name = '$settings{InputName}' is invalid!\nValid Input Names are: $validInputs");
996   }
997   $settings{InputNum} = $name2input{$settings{InputName}};
998 }
999
1000 outputSetting("InputName");
1001 outputSetting("InputNum");
1002
1003 if (!exists $CHANLIST{$settings{FrequencyTable}})
1004 {
1005   error(1, "Frequency Table = '$settings{FrequencyTable}' is invalid!");
1006 }
1007
1008 outputSetting("FrequencyTable");
1009
1010 # only validate the channel if the input is a tuner.
1011 if ($inputs[$settings{InputNum}] =~ /Tuner/)
1012 {
1013   if ($settings{TunerNum} !~ /^(\d)$/)
1014   {
1015     error(1, "TunerNum = '$settings{TunerNum}' is invalid!");
1016   }
1017   if (exists $opts{F} || exists $opts{frequency} || $settings{Frequency}) # the user may have specified a Frequency in their config file
1018   {
1019     if ($settings{Frequency} !~ /^(\d+)$/)
1020     {
1021       error(1, "Frequency = '$settings{Frequency}' is invalid!");
1022     }
1023     $settings{Channel} = "freq-$settings{Frequency}"# make sure we output the channel part.
1024   }
1025   # now verify that the channel exists in the frequency table!
1026   else
1027   {
1028     if (!$settings{Channel})
1029     {
1030       error(1, "channel = '$settings{Channel}' is invalid!");
1031     }
1032 ## start new MMM # first verify the freqency table is appropriate for the standard (NTSC, PAL, SECAM),
1033     # unless they specified the frequency to tune to.
1034     if ($settings{FrequencyTable} !~ /^(custom|$settings{VideoStandard})/i)
1035     {
1036       error(1, "You specified Video Standard '$settings{VideoStandard}' which is incompatible with Frequency Table '$settings{FrequencyTable}'!");
1037     } ## end  new MMM
1038     if (!exists $CHANLIST{$settings{FrequencyTable}}->{$settings{Channel}})
1039     {
1040       error(1, "Channel = '$settings{Channel}' does not exist in Frequency Table '$settings{FrequencyTable}'!");
1041     }
1042   }
1043
1044   outputSetting("Channel");
1045   outputSetting("Frequency");
1046
1047   # get the current channel/frequency value.
1048   my $Frequency;
1049   if(($Frequency = $ivtvObj->getFrequency($tunerFD, $settings{TunerNum})) > 0)
1050   {
1051     my $freq = ($Frequency * 1000) / 16;
1052     print "freq = $freq\n" if ($settings{Debug});
1053     # find the associated channel.
1054     if ((!exists $opts{F} && !exists $opts{frequency} && !$settings{Frequency}) && ($curstd eq $settings{VideoStandard}) )
1055     {
1056       foreach my $chan (keys %{$CHANLIST{$settings{FrequencyTable}}})
1057       {
1058         if ($CHANLIST{$settings{FrequencyTable}}->{$chan} == $freq)
1059         {
1060           $curChannel = $chan;
1061         }
1062       }
1063       print "curChannel = $curChannel\n" if ($settings{Debug});
1064     }
1065     else
1066     {
1067       $curFrequency = $freq;
1068     }
1069   }
1070   elsif ($Frequency < 0)
1071   {
1072     die "Error: getFrequency() failed!\n";
1073   }
1074 }
1075 else
1076 {
1077   # set the channel = "" so we know to ignore it.
1078   $settings{Channel} = "";
1079 }
1080
1081 if ($settings{UsingIvtvDriver})
1082 {
1083   # validate the Codec related stuff.
1084   if ($settings{BitrateMode} !~ /^(0|1)$/)
1085   {
1086     error(1, "BitrateMode = '$settings{BitrateMode}' is invalid!");
1087   }
1088   if ($settings{Bitrate} < $settings{minBitrate} || $settings{Bitrate} > $settings{maxBitrate})
1089   {
1090     error(1, "Bitrate = '$settings{Bitrate}' is invalid!");
1091   }
1092   if ($settings{PeakBitrate} < $settings{Bitrate})
1093   {
1094     error(1, "PeakBitrate can not be less than Bitrate!");
1095   }
1096   elsif ($settings{PeakBitrate} == $settings{Bitrate} && !$settings{BitrateMode} == 1)
1097   {
1098     error(1, "PeakBitrate can not be equal to Bitrate in VBR Mode!");
1099   }
1100   elsif ($settings{PeakBitrate} < $settings{minPeakBitrate} || $settings{PeakBitrate} > $settings{maxPeakBitrate})
1101   {
1102     error(1, "PeakBitrate = '$settings{PeakBitrate}' is invalid!");
1103   }
1104
1105   if ($settings{VideoStandard} !~ /^(NTSC)/)
1106   {
1107     my $warn = 0;
1108     if ($settings{Framerate} == 0)
1109     {
1110       $settings{Framerate} = 1;
1111       $warn = 1;
1112     }
1113     if ($settings{FramesPerGOP} == 15)
1114     {
1115       $settings{FramesPerGOP} = 12;
1116       $warn = 1;
1117     }
1118     if ($warn)
1119     {
1120       print "Warning:  Setting Framerate/FramesPerGOP to PAL settings for Video Standard '$settings{VideoStandard}'!\n\nYou should either specify on the command line or in the ~/.ivtvrc config file.\n";
1121     }
1122   }
1123   elsif ($settings{VideoStandard} =~ /^(NTSC)/)
1124   {
1125     my $warn = 0;
1126     if ($settings{Framerate} == 1)
1127     {
1128       $settings{Framerate} = 0;
1129       $warn = 1;
1130     }
1131     if ($settings{FramesPerGOP} == 12)
1132     {
1133       $settings{FramesPerGOP} = 15;
1134       $warn = 1;
1135     }
1136     if ($warn)
1137     {
1138       print "Warning:  Setting Framerate/FramesPerGOP to NTSC settings for Video Standard '$settings{VideoStandard}'!\n\nYou should either specify on the command line or in the ~/.ivtvrc config file.\n";
1139     }
1140   }
1141
1142   if ($settings{StreamType} < 0 || $settings{StreamType} > 14)
1143   {
1144     error(1, "StreamType = '$settings{StreamType}' is invalid!");
1145   }
1146  
1147   if ($settings{CaptureLastGOP} < 0 || $settings{CaptureLastGOP} > 1)
1148   {
1149     error(1, "CaptureLastGOP = '$settings{CaptureLastGOP}' is invalid!");
1150   }
1151
1152   outputSetting("BitrateMode");
1153   outputSetting("Bitrate");
1154   outputSetting("PeakBitrate");
1155   outputSetting("SetMSPMatrix");
1156   outputSetting("MSPInput");
1157   outputSetting("MSPOutput");
1158   outputSetting("Framerate");
1159   outputSetting("FramesPerGOP");
1160   outputSetting("Aspect");
1161   outputSetting("AudioBitmask");
1162   outputSetting("BFrames");
1163   outputSetting("DNRMode");
1164   outputSetting("DNRSpatial");
1165   outputSetting("DNRTemporal");
1166   outputSetting("DNRType");
1167   outputSetting("GOPClosure");
1168   outputSetting("Pulldown");
1169   outputSetting("StreamType");
1170   outputSetting("CaptureLastGOP");
1171 }
1172
1173 # update the config file if the user wants us to.
1174 if ($settings{UpdateConfigFile})
1175 {
1176   my $profile;
1177   if (@profileNames > 1)
1178   {
1179     print "Warning:  Not updating config file as you have more than 1 profile specified!\n";
1180   }
1181   elsif (@profileNames == 1)
1182   {
1183     $profile = $profileNames[0];
1184   }
1185   else
1186   {
1187     $profile = "defaults";
1188   }
1189   if ($profile)
1190   {
1191     my $createProfile = (exists $configIni{$profile} ? 0 : 1);
1192     print "Creating Profile = '$profile': $createProfile\n" if ($settings{Debug});
1193
1194     if (!$settings{UseConfigFile})
1195     {
1196       # we have to create the config file and tie to it.
1197       tie %configIni, 'Config::IniFiles', () or die "Error: Initializing config file '$settings{ConfigFileName}' failed! $!\n";
1198
1199       # now set the name to work with.
1200       tied(%configIni)->SetFileName($settings{ConfigFileName}) or die "Error: Setting config file to '$settings{ConfigFileName}' failed! $!\n";
1201
1202       $configIni{$profile} = {};  # make sure the section exists.
1203     }
1204
1205     foreach my $arg (keys %mappings)
1206     {
1207       foreach my $option (split(/\|/, $mappings{$arg})) # handle the long/short command option versions
1208       {
1209         if (exists $configIni{$profile}{$arg} || $createProfile || exists $opts{$option})
1210         {
1211           $configIni{$profile}{$arg} = $settings{$arg};
1212           print "configIni{$profile}{$arg} = '" . $settings{$arg} . "'\n" if $settings{Debug};
1213           last;
1214         }
1215       }
1216     }
1217
1218     # write the config file out.
1219     tied(%configIni)->RewriteConfig or die "Error: Writing config file '$settings{ConfigFileName}' failed!  $!\n";
1220   }
1221 }
1222
1223 # this hash keeps track of those values I have to set back.
1224 my %changedSettings = (
1225     resolution => 0,
1226     standard => 0,
1227     VideoType => 0,
1228     InputNum => 0,
1229     Channel => 0,
1230     Frequency => 0,
1231     codec => 0,
1232     );
1233
1234 # change the channel
1235 if ($inputs[$settings{InputNum}] =~ /Tuner/)
1236 {
1237   if (exists $opts{F} || exists $opts{frequency} || $settings{Frequency})
1238   {
1239     if ($settings{Frequency} != $curFrequency)
1240     {
1241       $changedSettings{Frequency} = 1;
1242       tuneFrequency($settings{Frequency});
1243     }
1244   }
1245   else
1246   {
1247     if ($curstd ne $settings{VideoStandard})
1248     {
1249       # we have to set the channel regardless.
1250       # but we want to tune back to the previous frequency.
1251       $changedSettings{Frequency} = 1;
1252       changeChannel($settings{Channel});
1253     }
1254     elsif ($settings{Channel} ne $curChannel)
1255     {
1256       # otherwise we just changeChannel and restore the previous channel.
1257       $changedSettings{Channel} = 1;
1258       changeChannel($settings{Channel});
1259     }
1260   }
1261 }
1262
1263 # set the video standard
1264 if ($settings{VideoStandard} ne $curstd)
1265 {
1266   $changedSettings{standard} = 1;
1267   change_standard();
1268 }
1269
1270 # set the input
1271 if ($settings{InputNum} != $curinput || $settings{InputName} ne $curinputName)
1272 {
1273   $changedSettings{InputNum} = 1;
1274   if (!(exists $opts{i} || exists $opts{inputnum} || exists $opts{I} || exists $opts{inputname} || exists $profileOverloads{InputNum} || exists $profileOverloads{InputName}))  # our defaults are different than the current values!
1275   {
1276     print "Warning:  Changing input from '$curinputName' to'$settings{InputName}'.\n";
1277   }
1278   change_input();
1279 }
1280
1281 # set the capture type
1282
1283 # store the current width,height so we can restore afterwards
1284 my ($oldWidth, $oldHeight) = $ivtvObj->getResolution($tunerFD);
1285 print "oldWidth = '$oldWidth', oldHeight = '$oldHeight'\n" if ($settings{Debug});
1286
1287 if ($settings{VideoWidth} != $oldWidth || $settings{VideoHeight} != $oldHeight)
1288 {
1289   $changedSettings{resolution} = 1;
1290 }
1291
1292 # specify the width,height to capture
1293 if ($changedSettings{resolution})
1294 {
1295   $result = $ivtvObj->setResolution($tunerFD, $settings{VideoWidth}, $settings{VideoHeight});
1296   if (not defined $result)
1297   {
1298     die "Error calling setResolution!\n";
1299   }
1300   if (!$result)
1301   {
1302     die "Error in setResolution ioctl call!\n";
1303   }
1304 }
1305
1306 if ($settings{UsingIvtvDriver})
1307 {
1308   # set the GOP_END flag if the user requested it.
1309   if ($ivtvVersion > 265) # > 0.1.9
1310   {
1311     $result = $ivtvObj->setEndGOP($tunerFD, $settings{CaptureLastGOP});
1312     if (!$result)
1313     {
1314 ## L1312 macmil_co_jp MMM    die "Error calling setEndGOP($settings{CaptureLastGOP})!\n";
1315     }
1316   }
1317  
1318   # specify the codec options to capture mpeg's at.
1319   foreach my $codecName (keys %codecMappings)
1320   {
1321     my $codecIndex = $ivtvObj->{codecIndexes}{$codecMappings{$codecName}};
1322     if ($codecInfo[$codecIndex] != $settings{$codecName})
1323     {
1324       $changedSettings{codec} = 1;
1325       $newCodecInfo[$codecIndex] = $settings{$codecName};
1326       print "new $codecName = '$settings{$codecName}', old $codecName = '$codecInfo[$codecIndex]'\n" if $settings{Debug};
1327     }
1328   }
1329 }
1330
1331 if ($changedSettings{codec})
1332 {
1333   $result = $ivtvObj->setCodecInfo($tunerFD, @newCodecInfo);
1334   if (!$result)
1335   {
1336 ## L1334 macmil_co_jp MMM    die "Error calling setCodecInfo()!\n";
1337   }
1338 }
1339
1340 if (!$settings{DontRecord})
1341 {
1342   close($settingsFH) if ($settings{OutputSettings});
1343
1344   # capture the video/audio to video.mpg
1345   captureVideo(directoryName => $directoryName, RecordDuration => $settings{RecordDuration},
1346               OutputFileName => $settings{OutputFileName}, tuner => $tuner);
1347 }
1348
1349 if ($settings{ResetCardSettings} && !$settings{DontRecord})
1350 {
1351   # close and re-open the device since it appears to not like taking new settings if we ended capturing.
1352   close($tuner);
1353   sysopen($tuner, $settings{VideoDevice}, O_RDWR) or die "Error unable to open '$settings{VideoDevice}': $!";
1354   $tunerFD = fileno($tuner);
1355  
1356   # restore Codec values
1357   if ($changedSettings{codec})
1358   {
1359     $result = $ivtvObj->setCodecInfo($tunerFD, @codecInfo);
1360     if (!$result)
1361     {
1362 ## L1360 macmil_co_jp MMM      die "Error calling setCodecInfo()!\n";
1363     }
1364   }
1365
1366   # restore the previous input setting
1367   if ($changedSettings{InputNum})
1368   {
1369     # reset back to the old input name
1370     $settings{InputName} = $curinputName;
1371     change_input();
1372   }
1373
1374   # restore the previous video standard
1375   if ($changedSettings{standard})
1376   {
1377     $settings{VideoStandard} = $curstd;
1378     change_standard();
1379   }
1380
1381   # restore the previous width,height settings
1382   if ($changedSettings{resolution})
1383   {
1384     $result = $ivtvObj->setResolution($tunerFD, $oldWidth, $oldHeight);
1385     if (not defined $result)
1386     {
1387       die "Error calling setResolution!\n";
1388     }
1389     if (!$result)
1390     {
1391       die "Error in setResolution ioctl call!  result = '$result', oldWidth = '$oldWidth', oldHeight = '$oldHeight'\n";
1392     }
1393   }
1394
1395   # restore the previous channel
1396   if ($changedSettings{Channel} && $curChannel > 0)
1397   {
1398     changeChannel($curChannel);
1399   }
1400   if ($changedSettings{Frequency} && $curFrequency > 0)
1401   {
1402     tuneFrequency($curFrequency);
1403   }
1404 }
1405
1406 # close the tuner device
1407 close($tuner);
1408
1409 exit 0;
1410
1411 # usage(returnValue, ErrorString)
1412 # returnValue = 1 or 0
1413 # ErrorString = message you want to tell the user, but only if returnValue = 1.
1414 sub usage
1415 {
1416   my $errorCode = shift;
1417   my $error = shift;
1418
1419   print $usageStr;
1420   print "\nError:  $error\n" if ($errorCode == 1);
1421   print "$error\n" if ($errorCode == 2);
1422
1423   exit $errorCode;
1424 }
1425
1426 # error(returnValue, ErrorString)
1427 # returnValue = 1 or 0
1428 # ErrorString = message you want to tell the user.
1429 sub error
1430 {
1431   my $errorCode = shift;
1432   my $error = shift;
1433
1434   print "$versionStr";
1435   print "\nError:  $error\n";
1436
1437   exit $errorCode;
1438 }
1439
1440 # changes the input to $settings{InputNum} as long as it isn't = $curinput
1441 sub change_input {
1442   my $preinput = $name2input{$settings{InputName}};
1443   if($preinput != $curinput)
1444   {
1445     $curinput = $preinput;
1446     print "input now $settings{InputName}, #$preinput\n" if ($settings{Debug});
1447     my $result = $ivtvObj->setInput($tunerFD, $preinput);
1448     if (!$result)
1449     {
1450       die "Error:  setInput($preinput) failed!\n";
1451     }
1452   }
1453 }
1454
1455 # changes the video standard to $settings{VideoStandard} as long as it isn't = $curstd
1456 sub change_standard {
1457   my $standard = $name2std{$settings{VideoStandard}};
1458   if($standard != $curStandard)
1459   {
1460     $curStandard = $standard;
1461     print "standard now $settings{VideoStandard}, #$standard\n" if ($settings{Debug});
1462 ## L1460 v060406.pl MMM   my $result = $ivtvObj->setStandard($tunerFD, $standard);
1463     if (!$result)
1464     {
1465 ## L1463 v060406.pl MMM      die "Error:  setStandard($standard) failed!\n";
1466     }
1467   }
1468 }
1469
1470 # changes the channel
1471 # takes the channel to change
1472 sub changeChannel
1473 {
1474   my $ch = shift;
1475   my $freq = $CHANLIST{$settings{FrequencyTable}}->{$ch};
1476   my $driverf = ($freq * 16)/1000;
1477
1478   print "Ch.$ch: $freq $driverf\n" if ($settings{Debug});
1479
1480   if (!$ivtvObj->setFrequency($tunerFD, $settings{TunerNum}, $driverf))
1481   {
1482     die "Error:  changeChannel($ch) failed!\n";
1483   }
1484 }
1485
1486 # tunes to the specified frequency
1487 # takes the frequency to tune to
1488 sub tuneFrequency
1489 {
1490   my $freq = shift;
1491   my $driverf = ($freq * 16)/1000;
1492
1493   print "freq: $freq $driverf\n" if ($settings{Debug});
1494
1495   if (!$ivtvObj->setFrequency($tunerFD, $settings{TunerNum}, $driverf))
1496   {
1497     die "Error:  tuneFrequency($freq) failed!\n";
1498   }
1499 }
1500
1501 my $done = 0;
1502
1503 sub catch_alarm {
1504   if ($settings{CaptureLastGOP})
1505   {
1506     $stopGOP = 1;  # signal we need to stop the stream and capture the last GOP.
1507   }
1508   else
1509   {
1510     $done = 1;  # signal we are done.
1511   }
1512 }
1513
1514 # does the actual video capturing work.
1515 # takes directoryName, RecordDuration, OutputFileName, tuner
1516 sub captureVideo
1517 {
1518   my %args = ( @_ );
1519   my $directoryName = $args{directoryName};
1520   my $RecordDuration = $args{RecordDuration};
1521   my $OutputFileName = $args{OutputFileName};
1522   my $tuner = $args{tuner};
1523   my $fname = "$directoryName/$OutputFileName";
1524
1525   # setup global variables, signal handlers, etc.
1526
1527   $SIG{ALRM} = \&catch_alarm;
1528   $SIG{INT}  = \&catch_alarm;  # handle Ctrl-C
1529
1530   # open the file for writing.
1531
1532   sysopen(OUTPUT, "$fname", O_CREAT | O_WRONLY | O_LARGEFILE) or die "Error creating file '$fname': $!\n";
1533
1534   alarm($RecordDuration);
1535   my $buf = "";
1536   while (!$done)
1537   {
1538     if ($stopGOP)
1539     {
1540       $stopGOP = 0;
1541       $ivtvObj->stopEncoding($tuner);
1542       $endStream = 1;
1543       $done = 1;  # signal we are done after this loop.
1544     }
1545     # read from the device and write to the file.  (16384) 32768
1546     my $bytes = read($tuner, $buf, 16384);
1547     if (!$bytes && $endStream)
1548     {
1549       last;
1550     }
1551     print OUTPUT $buf;
1552   }
1553
1554   # close the file
1555   close(OUTPUT);
1556 }
1557
1558 # returns the formatted directory string
1559 sub formatDirectoryString
1560 {
1561   my $temp = $settings{DirectoryFormatString};
1562   my $result = $settings{OutputDirectory};
1563   my %lookupTable = (
1564     "d" => `/bin/date "$settings{DateTimeFormatString}"`,
1565     "I" => $settings{InputName},
1566     "c" => $settings{Channel},
1567   );
1568
1569   # fixup the InputName value
1570   $lookupTable{I} =~ s/\s/_/g;
1571   # cleanup the trailing slash on the date
1572   chomp $lookupTable{d};
1573
1574   foreach my $option ("d", "I", "c")
1575   {
1576     $temp =~ s/\%$option/$lookupTable{$option}/g;
1577   }
1578
1579   $result .= "/" . ($temp ? "$temp/" : "");
1580
1581   return $result;
1582 }
1583
1584 sub outputSettingSetup
1585 {
1586   my $date = `/bin/date`; chomp $date;
1587
1588   if ($settings{OutputSettingsType} eq "shell")
1589   {
1590     print $settingsFH "# Settings for Recording made on $date.\n";
1591   }
1592   elsif ($settings{OutputSettingsType} eq "perl")
1593   {
1594     print $settingsFH "# Settings for Recording made on $date.\n";
1595     print $settingsFH "my %settings = ();\n";
1596   }
1597 }
1598
1599 # outputs the specified setting and it's value to the
1600 # settings file represented by $settingsFH in the
1601 # specified language.
1602 sub outputSetting
1603 {
1604   my $setting = shift;
1605   my $value = $settings{$setting};
1606  
1607   return if (!$settings{OutputSettings});
1608
1609   if ($settings{OutputSettingsType} eq "shell")
1610   {
1611     print $settingsFH "REC_" . uc($setting) . "=\"$value\"\n";
1612   }
1613   elsif ($settings{OutputSettingsType} eq "perl")
1614   {
1615     print $settingsFH "\$settings{$setting} = \"$value\";\n";
1616   }
1617 }
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。
track feed