ffmpeg -i video.mp4 -f hls -hls_time 9 -hls_playlist_type vod -hls_segment_filename "stream%3d.ts" stream.m3u8

ffmpeg -i video.mp4 -c:v libx264 -c:a aac -f hls -hls_time 9 -hls_playlist_type vod -hls_segment_filename "stream%3d.ts" stream.m3u8

default.conf.template

server {
  root /webroot;

  location ~* \.ts$ {
    types {
      video/MP2T ts;
    }
  }

  location ~* \.m3u8$ {
    types {
      application/vnd.apple.mpegurl m3u8;
      # application/x-mpegURL m3u8;
    }
  }
}

niconico: duration: 6s, application/vnd.apple.mpegurl, video/MP2T
(durationはキーフレームとかいろいろで勝手に変わるかも?)

ffmpeg -i video.mp4 \
  -acodec copy \
  -vcodec copy \
  -vbsf h264_mp4toannexb \
  -map 0 \
  -f segment \
  -segment_format mpegts \
  -segment_time 30 \
  -segment_list stream.m3u8 \
  -segment_list_flags \
  -cache stream%03d.ts

codecをコピーすると1ファイルのtsに出力されてしまう場合がある
libx264で再エンコードする

ffmpeg -i video.mp4 \
  -vcodec libx264 \
  -acodec aac \
  -vbsf h264_mp4toannexb \
  -map 0 \
  -f segment \
  -segment_format mpegts \
  -segment_time 6 \
  -segment_list stream.m3u8 \
  -segment_list_flags \
  -cache stream%03d.ts

6000秒、100分でstream999に到達

docker run --rm -it -v "$PWD/webroot:/webroot" -v "$PWD/default.conf.template:/etc/nginx/templates/default.conf.template" -p "127.0.0.1:8000:80" nginx:1.21

-start_number 1

$ ffmpeg -i video.mp4 -vcodec libx264 -acodec aac -f hls -hls_time 9 -hls_playlist_type vod -hls_segment_filename "%d.ts" -start_number 1 playlist.m3u8
ffmpeg version 4.2.4-1ubuntu0.1

hls.jsは必要(Chromeの場合)

<!DOCTYPE html>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/hls.js@1"></script>

<video
  id="video"
  src="./stream.m3u8"
  width="640"
  height="360"
  controls
></video>

<script>
  // https://github.com/video-dev/hls.js
  var video = document.getElementById('video');
  if (Hls.isSupported()) {
    var hls = new Hls();
    hls.loadSource(video.src);
    hls.attachMedia(video);
  }
  // HLS.js is not supported on platforms that do not have Media Source
  // Extensions (MSE) enabled.
  //
  // When the browser has built-in HLS support (check using `canPlayType`),
  // we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video
  // element through the `src` property. This is using the built-in support
  // of the plain video element, without using HLS.js.
  //
  // Note: it would be more normal to wait on the 'canplay' event below however
  // on Safari (where you are most likely to find built-in HLS support) the
  // video.src URL must be on the user-driven white-list before a 'canplay'
  // event will be emitted; the last video event that can be reliably
  // listened-for when the URL is not on the white-list is 'loadedmetadata'.
  else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    video.src = videoSrc;
  }
</script>

  • HLSメディアサーバ
    • MP4ファイルをアップロード
    • HLSに変換、永続化
    • m3u8, ts形式で配信
  • フロントエンド
    • メディアサーバ上のm3u8のURLをvideo.src(hls.loadSource)に設定
    • hls.jsで再生

メディアサーバ書くならNimかGoかな
PythonとかTypeScript/Node.jsより、シングルバイナリの理想を追い求めたい…

Nim AWS S3 SDKほしい

JSONポストすればいいんでしょ、というのはそうだけど…

AWS S3 APIに関する造詣とS3 SDKのインタフェースに詳しくないと作れないなぁ

Jester使ってNimサーバ書いてみたかったんだけどね

Goで書くか

なんかあるね(Live向け?

今回はLiveじゃなくてVODなのでどうかな

MP4(H264/aac)ファイルをアップロード
ffmpegでHLS形式(m3u8, ts)に変換
S3式オブジェクトストレージにアップロード
オブジェクトストレージから配布するときにm3u8のパスを活かせるか?

ファイルのアップロードのプログレスってfetch APIにまだ実装されていない?
XHRを使う必要があるかも

FastAPIがほしいよお…

シングルバイナリ云々も、結局動的ライブラリがあったらシングルバイナリにならないだろうなというのはあるな(起動時にファイルシステムに展開するような仕組みだったとして、LGPLどうなるんだ?)
あとPythonランタイムが数MBならまあ埋め込んでもいいのでは…
またGoをやる機会が…

FastAPIにしようか…
pyinstaller使ってバイナリに固める仕組み(CI)だけ作っておこう
Nuitkaでもいいかもしれんけど、シングルバイナリならなんとなくpyinstallerの方がいい説とかある?
NuitkaもシングルバイナリになるならVOICEVOX ENGINEで経験あるNuitkaにしたい感もある
まあどっちでもいいなー