動画をダイレクトにサーバから視聴する方法は他にもストリーミング系の仕組みがあるらしいのですが、Sinatraがストリーミングにうまく対応できてないような感じなので、ガチガチの配信ではなく「なんちゃってストリーミング動画配信」をする為のメモです。Appleが考案していてiOSとも親和性が高い技術なので採用しました。
環境
- Ubuntu 18.04.2 LTS (GNU/Linux 4.15.0-99-generic x86_64)
- Sinatra 2.0.5 (bundlerで起動する前提です)
- ffmpeg N-97994-g83fa39e
UbuntuとSinatraは既に環境に配置されているとします。
また、インストール作業用フォルダとffmpegのバイナリを格納するフォルダをhomeに作成します。
- ffmpeg_sources
- ffmpeg_build
- bin
ffmpegのインストール
ffmpegをaptでインストールするとlibfdk-aacが含まれていませんので、自分でカスタマイズインストールしなければなりません。libfdk-aacはHTTP Live Streamingを行うために必要な動画を細切れに分割してプレイリストファイルを作るのに必要です。
ffmpegで利用するコーデック群のライブラリをインストールする為に事前に必要なツール群のインストール
sudo apt-get update -qq && sudo apt-get -y install \
autoconf \
build-essential \
cmake \
git-core \
libass-dev \
libfreetype6-dev \
libgnutls28-dev \
libsdl2-dev \
libtool \
libva-dev \
libvdpau-dev \
libvorbis-dev \
libxcb1-dev \
libxcb-shm0-dev \
libxcb-xfixes0-dev \
pkg-config \
texinfo \
wget \
yasm \
zlib1g-dev
ffmpegで利用するコーデック群のライブラリのインストール
sudo apt-get install nasm
sudo apt-get install libx264-dev
sudo apt-get install libx265-dev libnuma-dev
sudo apt-get install libvpx-dev
sudo apt-get install libfdk-aac-dev
sudo apt-get install libmp3lame-dev
sudo apt-get install libopus-dev
ffmpegのビルド
cd ~/ffmpeg_sources && \
wget -O ffmpeg-snapshot.tar.bz2 https://ffmpeg.org/releases/ffmpeg-snapshot.tar.bz2 && \
tar xjvf ffmpeg-snapshot.tar.bz2 && \
cd ffmpeg && \
env PATH="$HOME/bin:$PATH" PKG_CONFIG_PATH="$HOME/ffmpeg_build/lib/pkgconfig" ./configure \
--prefix="$HOME/ffmpeg_build" \
--pkg-config-flags="--static" \
--extra-cflags="-I$HOME/ffmpeg_build/include" \
--extra-ldflags="-L$HOME/ffmpeg_build/lib" \
--extra-libs="-lpthread -lm" \
--bindir="$HOME/bin" \
--enable-gpl \
--enable-libass \
--enable-libfdk-aac \
--enable-libfreetype \
--enable-libmp3lame \
--enable-libopus \
--enable-libvorbis \
--enable-libvpx \
--enable-libx264 \
--enable-libx265 \
--enable-nonfree && \
env PATH="$HOME/bin:$PATH" make && \
make install
※gnutlsとlibaomはなんかエラーが出たので(今回は必要ないので)除外
テスト
今回は人気アニメ「ミンクの刃」をストリーミング配信で観てみましょう。
mp4形式に変換
sudo ffmpeg -i 'ミンクの刃 01.mkv' -vcodec copy 'ミンクの刃 01.mp4'
mp4形式からストリーミング配信用のHLS形式へ変換
sudo /home/ユーザ名/bin/ffmpeg -i 'ミンクの刃 01.mp4' -codec copy -vbsf h264_mp4toannexb -map 0 -f segment -segment_format mpegts -segment_time 5 -segment_list 'ミンクの刃 01'/playlist.m3u8 'ミンクの刃 01'/a%03d.ts
配信用サイトの作成
require 'sinatra'
require 'uri'
set :environment, :production
get '/' do
erb(:test);
end
get '/:file_name' do |file_name|
sendFilePath = "disk/live/minknoyaiba/#{file_name}";
if file_name.match(/.+m3u8$/) then
send_file(sendFilePath, :filename => file_name, :type => "application/vnd.apple.mpegurl");
else
send_file(sendFilePath, :filename => file_name, :type => "video/mp2t");
end
end
/source/onlineフォルダ内にtest.rbがあり、同フォルダ内にdiskフォルダが存在する環境です。minknoyaibaフォルダ内にはHLS用のプレイリスト(.m3u8)や分割動画ファイル(.ts)が入っていると思ってください。
先ほど「ミンクの刃 01」フォルダにHLSのファイル一式を変換したのに何故「minknoyaiba」フォルダに入れるのか?それはSinatraのsend_fileが日本語フォルダをうまく認識してくれないからです。
また外部から接続する為にset :environment, :production
しています。
<!DOCTYPE html>
<html>
<head>
<title>HTTP Live Streaming Example</title>
</head>
<body>
<video src="/playlist.m3u8" width="400" height="300" controls></video>
</body>
</html>
配信用サイトの起動
bundle exec ruby -I /source/class -C/source/online test.rb
この時点で以下にアクセスするとサイトで動画が見れます。
http://テスト用サーバのIP:4567/
次にiOS側で動画を観てみましょう。
iOSアプリの作成
// global require
#import <AVKit/AVKit.h>
#import <AVFoundation/AVFoundation.h>
// local require
@interface MagiTubeBase : AVPlayerViewController {
}
AVKitとAVFoundationをプロジェクトに追加しておいてください。
@implementation MagiTubeBase
-(void)viewDidLoad {
[super viewDidLoad];
__strong NSURL *url = [NSURL URLWithString:@"http://テスト用サーバのIP:4567/playlist.m3u8"];
__strong AVPlayerItem *item = [AVPlayerItem playerItemWithURL:url];
__strong AVPlayer *player = [AVPlayer playerWithPlayerItem:item];
self.player = player;
}
@end
おしまい
ミンクの刃面白いですよね!
最後に溶鉱炉の中に沈むミンクが最高にカッコイイ!🥺