2012年09月01日 07:45 [Edit]

tips - モバイルには高画質すぎるH.264動画を劣化ゼロで再生可能に

noplay

右の「このデバイスではこの動画は再生できません」状態を、たった一バイト変更するだけで直します。


以下のPerl Scriptで、こうするだけです

# デフォルトではlevel 4.1 に変更
% ch264level leveltoohigh.mp4
# level 3.1 に変更
% ch264level -l31 leveltoohigh.mp4

ch264level.pl

#!/usr/bin/env perl
#
# $Id: ch264level.pl,v 0.1 2012/08/31 18:13:16 dankogai Exp dankogai $
#
use strict;
use warnings;
use Getopt::Std;

getopts 'l:' => \my %opt;
my $level = $opt{l} || 41;

die <<"EOF" unless @ARGV;
$0 [-l] foo.mp4 bar.mp4
   default is 41 for H.264 level 4.1
  -l40 set  H.264 level to 4
  -l31 sets H.264 level to 3.1
  see http://en.wikipedia.org/wiki/H.264/MPEG-4_AVC#Levels
EOF
chlevel( $_, $level ) for @ARGV;

sub chlevel {
    my ( $path, $level ) = @_;
    open my $fh, '+<', $path or die "$path: $!";
  scan:
    while ( !eof($fh) ) {
        read $fh, my $header, 8;
        my $len = unpack( "N", $header );
        my $name = substr( $header, 4 );
        #warn "$name:$len";
        if ( $name eq 'moov' ) {
            read $fh, my $moov, $len - 8;
            if (
                $moov =~ s{(
                  trak.+
                    mdia.+
                      minf.+
                       stbl.+
                        stsd.+
                          avc1.+
                            avcC
                              \01..)(.) 
                }{ $1 . chr $level }emsx
              )
            {
                last scan if ord $2 == $level;
                warn sprintf "%s : %d -> %d\n", $path, ord $2, $level;
                seek $fh, -$len + 8, 1;    # rewind
                syswrite $fh, $moov;       # rewrite
                last scan;
            }
        }
        seek $fh, $len - 8, 1;
    }
    close $fh;
}

たった一バイトしか書き換えないので、何GBもあるフルHD動画も安心です。

解説

webMドM専用フォーマットであることがほぼ確実になった今や動画のデファクトスタンダードになった感がある、H.264。しかし「スタンダード」という割には、あっちの環境で難なく再生できてたのにこっちで出来なかったりという状況は未だに珍しくありません。

その理由のかなりの部分が、レベルの過剰申告にあることに今さらながら気づきました。

H.264 - Wikipedia
MPEG-2などと同様、目的用途別に定義された機能の集合を表すプロファイルと、処理の負荷や使用メモリ量(これらは画面解像度やフレームレートに影響する)を表すレベルが定義がされる。H.264に準拠する機器(又はビットストリームそのもの)はこのプロファイルとレベルによって性能(又はビットストリームをデコードするのに必要な性能)を表示することが多い。

つまり再生機器は、このプロファイルとレベルを確認して、自分がそれを再生できるかを判断しているわけです。当然なるべく低いプロファイル、なるべく低いレベルの方が対応機器は増えます。例えばiPhone 4Sは ハイプロファイルレベル4.1 まで再生できますが、iPhone 4だとこれがメインプロファイルレベル3.1に下がり、iPhone 3GSに至ってはベースラインプロファイルまで下がってしまいます。

ところがiPhone 4でも余裕で再生できそうな、縮小しなくてもRetina Displayに収まってしまう動画がiPhone 4Sや新iPadで再生できなかったりするのです。そういう動画を調べてみると、レベル5.1とかになってたりするのです。

こんなメイジャーなやつまで。

% mp4info sm8628149.mp4 
mp4info version 1.9.1
sm8628149.mp4:
Track	Type	Info
1	video	H264 High@5.1, 219.000 secs, 507 kbps, 512x384 @ 30.000000 fps
2	audio	MPEG-4 AAC LC, 219.080 secs, 100 kbps, 44100 Hz

ニコ動のHTML5ページやiOSアプリだと何の問題もなく視聴できるのですが、ダウンロードしたファイルをWeb共有などで直見すると再生できませんでした。

どうみてもそんな過剰スペックは必要ありません。

% ffprobe sm8628149.mp4 
....
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'sm8628149.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 1
    compatible_brands: isom
    creation_time   : 2009-10-25 18:07:02
    copyright       : 
    copyright-eng   : 
  Duration: 00:03:39.08, start: 0.000000, bitrate: 610 kb/s
    Stream #0.0(und): Video: h264 (High), yuv420p, 512x384, 506 kb/s, 30 fps, 30 tbr, 30030 tbn, 60 tbc
    Metadata:
      creation_time   : 2009-10-25 07:46:14
    Stream #0.1(und): Audio: aac, 44100 Hz, stereo, s16, 100 kb/s
    Metadata:
      creation_time   : 2009-10-25 18:07:02

実際レベルを書き換えただけで何の問題もなく再生されるようになりました。

handbrake icon

実際 Handbrake のAppleTV 3用のプリセットを使ってエンコードしなおしたら、レベル3になりました。にも関わらずファイルサイズは小さくなりました。画質の劣化は肉眼では判別不能だと思います。

% mp4info sm8628149-appletv3.mp4
mp4info version 1.9.1
sm8628149-appletv3.mp4:
Track	Type	Info
1	video	H264 High@3, 219.100 secs, 317 kbps, 512x384 @ 29.981743 fps
2	audio	MPEG-4 AAC LC, 219.103 secs, 163 kbps, 44100 Hz
 Encoded with: HandBrake 0.9.8 2012071800

1080p@30FPSでも4.1で充分なはずなのに、なぜレベル5.1な動画がこんなに巷に溢れているのか。

ここからは憶測ですが、最高画質を目指すあまり、あまりに多くの人が手でレベルを設定してしまっているのではないでしょうか。そこはエンコーダーに任せるべきです。まともなエンコーダーであれば、無指定であればレベルを逆算して設定してくれるはずです。

まとめ

  • Mac/PCでは再生できるのにスマフォやタブレットで再生できなかったら、レベルを調べてみよう
  • 過剰レベルだとしたら、上のスクリプトなどでレベルを書き換えて試してみよう
    • 本来フルHD(1080p)でもHigh@4.1、HD(720p)でもMain@3.1でも充分なはず。5.1って4K2K用ですよ?
  • 再エンコードは最後の武器
    • 視聴者にそうさせないためにも、エンコーダー諸氏は適切なレベルの設定を!
    • 必要な発電所が減ったりして。

Dan the HD Blogger


この記事へのトラックバックURL