m2

ニコニコ動画の H.264 ビデオをなるべく高品質で iPod で見たい

ゆーすけべー日記: Plaggerでニコニコ動画を一括ダウンロード&変換 Podcast を生成して iPod touch で見る」を前提として。

問題点

方針

  • なるべく高品質で再変換する。

環境の違い

書いたもの

yaml(の一部):

  - module: Filter::FLVInfo
    rule:
      - expression: $args->{entry}->enclosure->type eq 'video/x-flv'
      - expression: "not -e File::Spec->catfile('/path/to/output', $args->{entry}->enclosure->filename . '.mp4')"

  - module: Filter::FFmpeg
    rule:
      expression: $args->{entry}->enclosure->type eq 'video/mp4'
    config:
      command: /opt/local/bin/ffmpeg
      ext: mp4
      dir: /path/to/output
      encoding: utf8
      noresize: 1
      extra_options: -coder 0 -level 13 -flags loop -deblockalpha 2 -qmin 21 -sameq -r 29.97
      options:
        video_codec:         libx264
        audio_codec:         copy

「noresize: 1」は私が勝手につけました。yaml からではサイズの指定を無効にできない(指定しないとデフォルトのサイズが設定される)ので、Filter::FFmpeg にちょっと手を加えます(sオプションを削除しているだけ)。

***************
*** 72,77 ****
--- 72,90 ----
              $ff->output_options($output_options);
          }
  
+         # noresize feature.
+         if ($self->conf->{noresize}) {
+             $context->log( info => 'no resize option detected.' );
+             my @opt = @{ $ff->options };
+             for ( my $i = 0; $i < @opt; $i++ ) {
+                 if ( $opt[$i] eq "-s" ) {
+                     splice @opt, $i, 2;
+                     $ff->options(@opt);
+                     last;
+                 }
+             }
+         }
+ 
          unless( -e $output_file ){
              $context->log( info => 'Converting ' . $enclosure->filename . ' ...' );
              my $result = $ff->exec();

extra_options の「-coder 0 -level 13」は iPod に転送するのに必要だそうです。

調べたところ、iPodビデオはベースラインプロファイルとかいう形式でないとだめらしく、その形式にするオプションが下記の2つらしい。

-coder 0 Baselineプロファイルに切り替え(-coder 0:cabac不使用 -coder 1:cabac使用)
-vlevel 13 Baselineプロファイル中のサポートレベル
http://d.hatena.ne.jp/shimibow/20060914/1158237089

「-flags loop -deblockalpha 2」はブロックノイズを減らせるっぽいです。

-deblockalpha
x264 の in-loop デブロックフィルタの強度パラメータ [-6〜6] の範囲で指定。
-flags loop でデブロックフィルタを ON にした場合のみ意味がある。-6:デブロック弱 <-> +6:デブロック強。 細部がつぶれすぎていると思ったら値を下げ、低ビットレート時のブロックノイズが気になるなら値を上げる。 十分にビットレートを割り当ててる場合は、そもそも -flags loop を指定せずでブロックフィルタを切ってしまうのも手。

最新ffmpeg/高度なオプション - MobileHackerz Knowledgebase Wiki

「-qmin 21」ですが、これが無いと

[libx264 @ 0x1416710]OVERFLOW levelcode=4377

が大量に出て、動画の一部がグレーになる現象が起こりました(かなりハマった)。
qmin は以下を参考にしました。

-qmin
q値の最小値 (デフォルト=2)
x264 ではデフォルトの qmin=2 は小さ過ぎる。少なくとも 10 以上にした方がよい。 qminが小さすぎるとソースによっては黒いバックなどの動きが少ないシーンでグレーの 靄がかかったようなフレーム ("Gray Fogged Frame") が出来てしまうことがある。

最新ffmpeg/高度なオプション - MobileHackerz Knowledgebase Wiki

「-sameq」は元のビデオと同じクオリティで変換するオプションです。が、やはり劣化するので、ファイルサイズを気にしなければ、ビットレートで大きい値を設定する方が良いかもしれません。

-sameq
ソースと同じクオリティで変換する。
-b, -bt, -qmax, -qmin, -qcomp, -qdiff, -maxrate, -bufsize 等のビットレート指定/品質コントロール系オプションは無視される

最新ffmpeg/ビデオオプション - MobileHackerz Knowledgebase Wiki


音に関しては「audio_codec: copy」としているので劣化は無いと思われます*1

あとダウンロード済みのビデオに対して毎回スリープが発生していたので、FetchNicoVideo.pm に手を入れて回避しました。かなり手抜き。

***************
*** 52,57 ****
--- 52,102 ----
      #get video_id
      my ($video_id) = $entry->link =~ m!www.nicovideo.jp/watch/(.*)!;
  
+     #set local path
+     my $filename = $self->conf->{id_as_filename} ? $video_id : $entry->title;
+     utf8::encode($filename);
+     if ( $self->conf->{filename_encode} ) {
+         Encode::from_to( $filename, "utf-8", $self->conf->{filename_encode} );
+     }
+ 
+     # ignore when the local file exists.
+     if ( -e File::Spec->catfile($self->conf->{dir}, $filename . ".mp4")) {
+         $context->log(info => "Exist File: $video_id");
+         my $path = File::Spec->catfile($self->conf->{dir}, $filename . ".mp4");
+         my $enclosure = Plagger::Enclosure->new;
+         $enclosure->filename($filename);
+         $enclosure->local_path($path);    # set to be used in later plugins
+         $enclosure->length(-s $path);
+         $enclosure->media_type("video/mp4");
+         $enclosure->type(Plagger::Util::mime_type_of($path));
+         $entry->add_enclosure($enclosure);
+         return;
+     }
+     if ( -e File::Spec->catfile($self->conf->{dir}, $filename . ".swf")) {
+         $context->log(info => "Exist File: $video_id");
+         my $path = File::Spec->catfile($self->conf->{dir}, $filename . ".swf");
+         my $enclosure = Plagger::Enclosure->new;
+         $enclosure->filename($filename);
+         $enclosure->local_path($path);    # set to be used in later plugins
+         $enclosure->length(-s $path);
+         $enclosure->media_type("application/x-shockwave-flash");
+         $enclosure->type(Plagger::Util::mime_type_of($path));
+         $entry->add_enclosure($enclosure);
+         return;
+     }
+     if ( -e File::Spec->catfile($self->conf->{dir}, $filename . ".flv")) {
+         $context->log(info => "Exist File: $video_id");
+         my $path = File::Spec->catfile($self->conf->{dir}, $filename . ".flv");
+         my $enclosure = Plagger::Enclosure->new;
+         $enclosure->filename($filename);
+         $enclosure->local_path($path);    # set to be used in later plugins
+         $enclosure->length(-s $path);
+         $enclosure->media_type("video/x-flv");
+         $enclosure->type(Plagger::Util::mime_type_of($path));
+         $entry->add_enclosure($enclosure);
+         return;
+     }
+ 
      #get flv url
      my $res = $ua->get("http://www.nicovideo.jp/api/getflv?v=$video_id");
      my $q   = CGI->new( $res->content );
***************
*** 67,79 ****
      $enclosure->url( URI->new($flv_url) );
      $enclosure->media_type("video/x-flv");
  
-     #set local path
-     my $filename = $self->conf->{id_as_filename} ? $video_id : $entry->title;
-     utf8::encode($filename);
-     if ( $self->conf->{filename_encode} ) {
-         Encode::from_to( $filename, "utf-8", $self->conf->{filename_encode} );
-     }
- 
      $enclosure->url =~ m!^http://[^/]+(?:smilevideo|nicovideo)\.jp/smile\?(\w)=(?:[^.]+)\.\d+(?:low)?!;
      my %video_type_of = (
  			 v => 'flv',
--- 112,117 ----

extra_options に「-r 29.97」を追加。
http://www.nicovideo.jp/watch/sm2990910 が変換できてなかったので。

timebase not supported by mpeg 4 standard

Version: media-video/ffmpeg-0.4.9_p20060530 USE="aac imlib sdl truetype vorbis zlib -a52 -amr -debug -doc -dts -encode -ieee1394 -network -ogg -oss -test -theora -threads -v4l -x264 -xvid" 0 kB

Command: fmpeg -i 1.avi -f psp -r 29.970030 -b 768 -ar 24000 -ab 64 -s 320x240 M4V00001.MP4

Error: [mpeg4 @ 0x2ba7e3a0be70]timebase not supported by mpeg 4 standard Error while opening codec for output stream #0.0 - maybe incorrect parameters such as bit_rate, rate, width or height

Solution: I had to change -r 29.970030 to -r 29.97

Did you try -r 30000/1001? That should work.

Site Unavailable


追記
「-flags loop -deblockalpha 2」なんですが、なんか画面が白っぽくなっちゃいますね。外した方が良いかも。

お願い

よりよい方法があれば教えてください。

お願い2

port で ffmpeg のバージョンの下げる方法があれば教えてください。

*1:じゃあ「video_codec: copy」ではどうかというと、再生は開始されましたがやけに重たくてまともに再生されませんでした