ffmpeg にオプション loglevel, seg_max_retry を渡せるようにした. ログ出力モードを追加. master
authorsatomichan <git-kawasemi.20250926@...>
Sun, 5 Oct 2025 11:06:45 +0000 (20:06 +0900)
committersatomichan <git-kawasemi.20250926@...>
Sun, 5 Oct 2025 14:01:28 +0000 (23:01 +0900)
radiru2-dl.pl
rec-nhk-radio.pl

index ed5480de989e7a01d87a6999249de1a38764b05b..9bee35cae08164d836c9dd3d8083d93f38572858 100755 (executable)
@@ -41,9 +41,6 @@ use Encode;
 use XML::XPath;  #sudo apt install libxml-xpath-perl
 use XML::XPath::XMLParser;
 use Getopt::Long qw(:config posix_default no_ignore_case gnu_compat);
-#use Time::Piece;
-use IPC::Open3 qw(open3);
-use Symbol qw(gensym);
 sub dp;
 
 my $config_url = 'https://www.nhk.or.jp/radio/config/config_web.xml';
@@ -51,14 +48,19 @@ my $config_url = 'https://www.nhk.or.jp/radio/config/config_web.xml';
 
 
 # オプション解析
-my $is_check_mode   = 0;
-my $is_verbose_mode = 0;
-my $retry           = 5;
-GetOptions('check|c'   => \$is_check_mode,
-           'verbose|v' => \$is_verbose_mode,
-           'retry|r=i' => \$retry,
+my $is_check_mode        = 0;
+my $is_verbose_mode      = 0;
+my $ffmpeg_loglevel      = 'fatal'; #ログレベル fatal: 致命的なもののみ出力
+my $ffmpeg_seg_max_retry = 5;       #hls エラー発生時にセグメントを再読み込みする最大回数
+my $retry                = 5;
+GetOptions('check|c'                => \$is_check_mode,
+           'verbose|v'              => \$is_verbose_mode,
+           'ffmpeg-loglevel=s'      => \$ffmpeg_loglevel,
+           'ffmpeg-seg_max_retry=i' => \$ffmpeg_seg_max_retry,
+           'retry|r=i'              => \$retry,
            );
 my($station, $req_duration, $output) = @ARGV;
+$output = Encode::decode('UTF-8', $output);
 
 #HLS URL 取得
 $station = 'tokyo-r2' if $station eq 'r2';
@@ -85,10 +87,15 @@ for(my $try = 0; $try <= $retry; $try++){
 
     dp "try: $try    numbered_filename: $numbered_filename    this_duration: $this_duration";
 
-    $ret = system('ffmpeg', '-fflags',   '+discardcorrupt',  #破損したフレームを破棄
-                            '-loglevel', 'fatal',            #ログレベル 致命的なもののみ出力
-                            '-y',                            #Overwrite -> Yes
-                            '-i', $hls_url, '-t', $this_duration, $numbered_filename);
+    my $ffmpeg = 'ffmpeg -fflags +discardcorrupt '.              #破損したフレームを破棄
+                        "-loglevel $ffmpeg_loglevel ".
+                        "-seg_max_retry $ffmpeg_seg_max_retry ". #hls エラー発生時にセグメントを再読み込みする最大回数
+                        '-y '.                                   #Overwrite -> Yes
+                        "-i $hls_url ".
+                        "-t $this_duration ".
+                        "'$numbered_filename' ";
+    print Encode::decode('UTF-8', `$ffmpeg 2>&1`);
+    $ret = $? >> 8;
 
     #出力ファイルが存在する?
     next unless -f $numbered_filename;
@@ -130,10 +137,7 @@ sub get_hls_url {
 #ffmpeg で録音時間を取得 (秒数で返す)
 sub get_rec_duration_by_file {
     my($file) = @_;
-    my $err = gensym;
-    my $pid = open3(undef, undef, $err, "ffmpeg -i $file");
-    my $info = do { local $/; <$err> };
-    waitpid($pid, 0);
+    my $info  = do { local $/; `ffmpeg -i '$file' 2>&1` };
 
     if ($info =~ /Duration: (\d+:\d{2}:\d{2})\./) {
         return duration2sec($1);
index 84190f86228e00a2772bd57c3f9e6e3a8277ea0e..53fd5ebf55818777471cedc7344be7cd3067b227 100755 (executable)
@@ -58,14 +58,20 @@ die "保存先 $DIR_SAVE_TO に書き込み権限がありません."
 
 
 # オプション解析
-my $is_check_mode   = 0;
-my $is_verbose_mode = 0;
-my $offset_time_sec = 35; #開始オフセット(秒)
-my $end_margin_sec  = 30; #後方余白(秒)
-GetOptions('check|c'       => \$is_check_mode,
-           'verbose'       => \$is_verbose_mode,
-           'offset-time=i' => \$offset_time_sec,
-           'end-margin=i'  => \$end_margin_sec   );
+my $is_check_mode        = 0;
+my $is_verbose_mode      = 0;
+my $is_logging_mode      = 0;
+my $ffmpeg_loglevel      = '';
+my $ffmpeg_seg_max_retry = '';
+my $offset_time_sec      = 30; #開始オフセット(秒)
+my $end_margin_sec       = 40; #後方余白(秒)
+GetOptions('check|c'                => \$is_check_mode,
+           'verbose'                => \$is_verbose_mode,
+           'logging'                => \$is_logging_mode,
+           'ffmpeg-loglevel=s'      => \$ffmpeg_loglevel,
+           'ffmpeg-seg_max_retry=s' => \$ffmpeg_seg_max_retry,
+           'offset-time=i'          => \$offset_time_sec,
+           'end-margin=i'           => \$end_margin_sec   );
 
 
 
@@ -74,6 +80,9 @@ unless (@ARGV) {
        my $script_name = basename($0, '');
        my $usage = << "    EOM_USAGE";
     USAGE) $script_name [ -c | --check | --verbose ]
+                              [--logging]
+                              [--ffmpeg-loglevel <ffmpeg ログレベル>]
+                              [--ffmpeg-seg_max_retry <ffmpeg hls エラー リトライ回数>]
                               [--offset-time <開始オフセット(秒)>]
                               [--end-margin  <後方余白(秒)>]
                               <放送局ID> <録音開始日> <録音開始時刻> [<録音長さ(分)> <タイトル>]
@@ -85,6 +94,12 @@ unless (@ARGV) {
     --verbose を指定すると, job発行コマンドと番組表の内容を表示してからjob発行をする,
     冗長表示モード になります.
 
+    <ffmpeg ログレベル> ffmpeg の loglevel を info(ffmpegのデフォルト) や warning, quiet 等から指定します.
+    このコマンドにおけるデフォルトは fatal: 致命的なもののみ出力 です.
+
+    <ffmpeg hls エラー リトライ回数> hls エラー発生時にセグメントを再読み込みする最大回数を指定します.
+    デフォルトは 5回 です.
+
     <開始オフセット(秒)> には, 録音開始時刻の00秒から実際に録音を開始するまでの秒数を指定します.
     デフォルトは $offset_time_sec 秒です.
 
@@ -138,13 +153,20 @@ die "無効な引数です." unless ($y && $m && $d && $time_h <= 24 && $time_h
 
 my $file_name_base = sprintf('%04d-%02d-%02d_%02d%02d_nhk-%s_%s_%dmin', $y, $m, $d, $time_h, $time_m, $station, $title, $min);
 my $mp3 = "${file_name_base}.mp3";
+my $txt = "${file_name_base}.txt";
 
 my $duration = get_duration_string($min, $end_margin_sec);
 
 
 
 # コマンド構築
-my $rec_cmd = "cd $ENV{RADIKO_SAVE_TO}; $SLEEP $offset_time_sec; $DL $station $duration $mp3; $CHMOD $FILE_PERMISSION $file_name_base*.mp3; ";
+my $rec_cmd = "cd $ENV{RADIKO_SAVE_TO}; $SLEEP $offset_time_sec; ".
+              "$DL ".
+              (length $ffmpeg_loglevel      ? "--ffmpeg-loglevel $ffmpeg_loglevel "           : '').
+              (length $ffmpeg_seg_max_retry ? "--ffmpeg-seg_max_retry $ffmpeg_seg_max_retry " : '').
+              "$station $duration $mp3 ".
+              ($is_logging_mode ? ">> $txt; " : '; ').
+              "$CHMOD $FILE_PERMISSION $file_name_base*.mp3; ";
 my $at_time = sprintf('%d:%02d %02d.%02d.%02d', $time_h, $time_m, $d, $m, ($y - int($y/100)*100 )  );
 my $cmd     = qq{$ECHO -e '$BASH << EOC\\n$rec_cmd\\nEOC' | $AT "$at_time"};