しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

iPhone で縦向きに撮影した動画が Chrome や FFmpeg だと横向きになってしまう原因と対策

最近は動画を使ったアプリケーションを仕事で作っているのですが、その途中で iPhone を使って縦向きに撮影した動画が、アップロードして video タグで再生した場合に横向きになってしまう現象に遭遇しました。

具体的には以下のような感じです。

f:id:shiba-yan:20140707232417p:plain

これは Chrome に mp4 をドロップして再生させた状態ですが、HTML5 の video タグを使った場合も同様に横向きになってしまいました。

ちなみに FFmpeg を使って動画のサムネイルを作成した場合にも、同様に横向きの画像となってしまいます。

ffmpeg.exe -ss 3 -i daruyanagi.mp4 -vframes 1 -f image2 daruyanagi.jpg

実際に作成したサムネイルは以下のような感じ。

f:id:shiba-yan:20140707232807j:plain

これが全てのブラウザやプレイヤーで再現してくれれば iPhone の撮影時に問題があったことになるのですが、Internet Explorer や Windows Media Player では正しく縦向きの動画として再生されます。

f:id:shiba-yan:20140707233437p:plain

正直良く分からなかったので困っていたのですが、ふとファイルのプロパティを確認してみると実は横長の画像であることがわかりました。

f:id:shiba-yan:20140707233536p:plain

なので、FFmpeg を使ってもっと詳細なファイル情報を出力してみることにしました。

ffmpeg.exe -i daruyanagi.mp4

パラメータとして -i だけを指定するとビットレートなどの基本的な情報から、動画に埋め込まれているメタデータなど様々な情報を得ることが出来ます。

実行した結果を長いですが載せておきます。

ffmpeg version N-64477-g5864069 Copyright (c) 2000-2014 the FFmpeg developers
  built on Jul  6 2014 22:02:08 with gcc 4.8.3 (GCC)
  configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libcaca --enable-libfreetype --enable-libgme --enable-libgsm --enable-libilbc --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-decklink --enable-zlib
  libavutil      52. 90.101 / 52. 90.101
  libavcodec     55. 68.101 / 55. 68.101
  libavformat    55. 45.100 / 55. 45.100
  libavdevice    55. 13.101 / 55. 13.101
  libavfilter     4. 10.100 /  4. 10.100
  libswscale      2.  6.100 /  2.  6.100
  libswresample   0. 19.100 /  0. 19.100
  libpostproc    52.  3.100 / 52.  3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'daruyanagi.mp4':
  Metadata:
    major_brand     : qt  
    minor_version   : 0
    compatible_brands: qt  
    creation_time   : 2014-06-14 10:58:39
    encoder         : 7.1.1
    encoder-jpn     : 7.1.1
    date            : 2014-06-14T19:58:39+0900
    date-jpn        : 2014-06-14T19:58:39+0900
    location        : +33.8390+132.7707+041.785/
    location-jpn    : +33.8390+132.7707+041.785/
    model           : iPhone 5s
    model-jpn       : iPhone 5s
    make            : Apple
    make-jpn        : Apple
  Duration: 00:00:13.03, start: 0.000000, bitrate: 17084 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080, 16991 kb/s, 29.98 fps, 29.97 tbr, 600 tbn, 1200 tbc (default)
    Metadata:
      rotate          : 90
      creation_time   : 2014-06-14 10:58:39
      handler_name    : Core Media Data Handler
      encoder         : H.264
    Side data:
      displaymatrix: rotation of -90.00 degrees
    Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 62 kb/s (default)
    Metadata:
      creation_time   : 2014-06-14 10:58:39
      handler_name    : Core Media Data Handler
At least one output file must be specified

注目すべきは Metadata にある rotate: 90 という表示ですね。結局は System.Drawing が画像の方向を無視するので対応した話 - しばやん雑記 と同じように回転情報だけを持っていて、プレイヤー側で対応しろということなのでした。

ちなみにもう少し仕様を調べたところ、mp4 というか mov は Exif のような単純な仕様とは異なり、メタデータとして変換行列を持っているらしいですね。

QuickTime File Format Specification: Basic Data Types

そして、結局 Chrome でも正しい向きで再生するためには、メタデータの変換情報を削除して再エンコードするしかないみたいです。そして FFmpeg を使ってサムネイルを作成する場合には回転のフィルタだけ掛けてあげれば良さそうですね。