ffmpegのinputでhttpプロトコルを使うときにcookieをセットする

ffmpegのhttpプロトコルでcookie送信する方法、ググってもドキュメント以外あんまり有益な情報見つけられなかったので、試行錯誤してうまくいった結果を残しておこうと思いました。

## 前提

この記事ではMacにhomebrewでインストールした`ffmpeg version 2.7.2`を使用しています。

## ffmpegで使用できるプロトコル

ffmpegはinputやoutputで様々なプロトコルを使うことができます。

```sh
$ ffmpeg -protocols
```

を実行すると使用できるプロトコルが確認できます。

```sh
ffmpeg version 2.7.2 Copyright (c) 2000-2015 the FFmpeg developers
  built with Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/2.7.2_1 --enable-shared --enable-pthreads --enable-gpl --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-opencl --enable-libx264 --enable-libmp3lame --enable-libvo-aacenc --enable-libxvid --enable-vda
  libavutil      54. 27.100 / 54. 27.100
  libavcodec     56. 41.100 / 56. 41.100
  libavformat    56. 36.100 / 56. 36.100
  libavdevice    56.  4.100 / 56.  4.100
  libavfilter     5. 16.101 /  5. 16.101
  libavresample   2.  1.  0 /  2.  1.  0
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  2.100 /  1.  2.100
  libpostproc    53.  3.100 / 53.  3.100
Supported file protocols:
Input:
  cache
  concat
  crypto
  data
  ffrtmphttp
  file
  ftp
  gopher
  hls
  http
  httpproxy
  https
  mmsh
  mmst
  pipe
  rtmp
  rtmps
  rtmpt
  rtmpts
  rtp
  srtp
  subfile
  tcp
  tls
  udp
  udplite
  unix
Output:
  crypto
  ffrtmphttp
  file
  ftp
  gopher
  http
  httpproxy
  https
  icecast
  md5
  pipe
  rtmp
  rtmps
  rtmpt
  rtmpts
  rtp
  srtp
  tcp
  tls
  udp
  udplite
  unix
```

予想以上にいろいろ使える。

ここではffmpegのinputとしてhttpプロトコルを使い、cookieをリクエストに含めて送信することをやってみます。cookieで認証管理などをしている動画URL[^1]とかの場合に使い道があると思います。

## httpプロトコルをcookieを設定して使う例

httpプロトコルを使用する場合、`-cookies`オプションを利用できます。

```sh
$ ffmpeg -cookies 'session=xxxxxx; domain=.example.com; path=/
history=yyyyyy; domain=.example.com; path=/
token=zzzzzz; domain=.example.com; path=/' -i 'http://www.example.com/video.mp4' -ss 0 -vframes 1 output.jpg
```

上記は`http://www.example.com/video.mp4`の動画URLに対して、3つのcookieが設定されたリクエストを送信し、サムネイルを取得する例です。

重要なのはオプションの順番です。`-i`オプションより前に`-cookies`オプションを記述する必要があります。逆にするとcookieがリクエストにセットされません。ここで結構はまりました。ffmpegを使うときはオプションの順番を常に意識しておいた方が良いです。ドキュメントにも書いてある。

> As a general rule, options are applied to the next specified file. Therefore, order is important,

[ffmpeg Documentation > Description](https://ffmpeg.org/ffmpeg.html#Description)

また、cookieを複数設定する場合はcookieごとに改行する必要があり、それぞれのcookieはname,valueの他にdomainとpathも必須です。指定していない場合、

```shell-session
Invalid cookie found, no value, path or domain specified
```

のようなエラーになります。

[ffmpeg Documentation > HTTP Cookies](https://www.ffmpeg.org/ffmpeg-all.html#HTTP-Cookies)

## リクエストヘッダー確認方法

ffmpegコマンド実行時のhttpリクエストヘッダーが知りたい場合は`-loglevel`オプションに`debug`を指定すると確認できます。

cookieの設定がうまくいかない場合は確認してみましょう。

```sh
$ ffmpeg -cookies 'session=xxxxxx; domain=.example.com; path=/
history=yyyyyy; domain=.example.com; path=/
token=zzzzzz; domain=.example.com; path=/' -i 'http://www.example.com/video.mp4' -ss 0 -vframes 1 -loglevel debug output.jpg


# ..中略

Reading option '-cookies' ... matched as AVOption 'cookies' with argument 'session=xxxxxx; domain=.example.com; path=/
history=yyyyyy; domain=.example.com; path=/
token=zzzzzz; domain=.example.com; path=/'.
Reading option '-i' ... matched as input file with argument 'http://www.example.com/video.mp4'.
Reading option '-ss' ... matched as option 'ss' (set the start time offset) with argument '0'.
Reading option '-vframes' ... matched as option 'vframes' (set the number of video frames to output) with argument '1'.
Reading option '-loglevel' ... matched as option 'loglevel' (set logging level) with argument 'debug'.
Reading option 'output.jpg' ... matched as output file.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option loglevel (set logging level) with argument debug.
Successfully parsed a group of options.
Parsing a group of options: input file http://www.example.com/video.mp4.
Successfully parsed a group of options.
Opening an input file: http://www.example.com/video.mp4.
[http @ 0x7f8003626a40] request: GET /video.mp4 HTTP/1.1
User-Agent: Lavf/56.36.100
Accept: */*
Range: bytes=0-
Connection: close
Host: www.example.com
Cookie: session=xxxxxx; history=yyyyyy; token=zzzzzz  # <- ここ
Icy-MetaData: 1

# ..以下略
```

この場合はちゃんとリクエストヘッダーにcookieが設定されていますね。

## httpプロトコルのその他オプション

`-headers`オプションがあるので、ここで直接cookieを指定したりもできます。また、ffmpegを使って定期的に外部URLを読み込むようなプログラムを作る場合は`-user-agent`オプションを設定しておくとお行儀がよさそうですね。

他にもたくさんあります。詳しくはドキュメントを読んでみてください。

[ffmpeg Documentation > http](https://www.ffmpeg.org/ffmpeg-all.html#http)

[^1]: ニコニコ動画とか