📽️

ストリーミングとは何か、、、調べてみた経験より(2020-09-19)

2024/06/26に公開

はじめに

畑田です。
開発の要件の中にストリーミングが含まれており、そもそもストリーミングとは何か、その実現方法や、手法の選択肢には何があるのか気になって調べてみました。
サブタイトルはAWSでストリーミングを試してみた経験より。

ストリーミングとは

そもそもストリーミングが何なのかがイマイチよくわかっていなかったので調べました。
ストリーミングとはマルチディアファイルのダウンロード方式の一つです。
通常htmlなどに画像を載せるとき、<img src="../img/some.jpg">などとすると思いますが、これはメディアがダウンロードが完了して初めて描画される様式です。
動画に関しても同じです。
<video src="../video/some.mp4">などと書いているとダウンロードに時間がかかってしまい、再生するまでその完了を待つ必要があります。
これに対しストリーミングは、必要な部分をダウンロードしながら再生し、残りのデータもダウンロードしていく方式であるので、再生までの待ち時間を大幅に短縮できるのです。
自分はストリーミングというとライブストリーミングだけだと思い込んでいたのですが、生放送にだけではなく通常のオンデマンド動画再生の際にもよく使われています。
そしてもちろん、ストリーミングにもプロトコル(決まった方式や規格、規則)があります。以下の2つは多くのブラウザで標準対応しているものです。

  • HLS (HTTP Live Streaming)
  • MPEG-DASH (Dynamic Adaptive Streaming over HTTP)

HLS

では、HLSとは何かという話

HLSはApple Inc.製のストリーミングプロトコルであり、IETFの規格としてリリースされています。
これはもともとQuickTimeやSafari、iOS、macOS向けに開発されたものですが、ほぼ全てのブラウザに対応しています。
再生するクライアントの環境に合わせてビットレートを調整してくれるadaptive bitrate streamingを採用しています。
名前の通り、HTTPに基づいた通信を行うため、普通のweb server (nginxとかApache)を用いてマルチディアを配布できてしまう上、firewallなども問題になりません。
HLSはメディアセグメントと、プレイリストによってストリーミングを行います。
HLSではセグメントはFragmented MP4形式(拡張子は.m4s)もしくはMPEG-2 TS形式(拡張子は.ts)、プレイリストはM3U形式(拡張子は.m3uまたは.m3u8)のファイルで表現します。(ちなみにM3UはMP3 URLの略で、TSはtransport streamingの略です。)
TSファイルはメディアセグメント(細切れのメディア)を、M3Uファイルはプレイリストを保存しており、これをHTTP GETで取得することでストリーミングが実現されます。

Fragmented MP4とは

その名の通り、細かく分割されたMP4形式のファイルのことです。
MP4形式については<a href="./media_type.md">こちら</a>。
形式は通常のMP4とやや似ていますが、通常のMP4がftyp, moov, mvhd, trak, mdat, video dataを持っている一方で、Fragmented MP4はinitial segmentが、ftyp, moov, mvhd, trakを持ち、それ以外のセグメントで、moof, mfhd, traf, mdat, video dataを持つという風に情報の持ち方が異なります。
TSファイルと比較すると、対応するcodecの違いの他に、M3Uファイルの書き方が多少変わります。
HLSではバージョン4からしかFragmented MP4に対応しておらず、これ以降のバージョンでも#EXT-X-MAP:URI="init.m4s"という行を加えてあげる必要があります。

TSファイルとは

TSファイルは、再生するメディアが分割されて保存されたメディアセグメントです。
これは地デジ(地上デジタル波放送)と同じらしいです。
内容のメディアは映像であればH.264、H.265が、音声であればAAC、MP3などのcodecが対応しているようです。
TSファイルは再生するメディアを非常に細かく分割したものであり、その持続時間が10秒(Apple推奨)とかなので、一つのメディアに対して大量に生成されます。
これらをM3Uファイルの指示に従って逐次ダウンロードすることで、待ち時間を短縮しているのです。

M3Uファイルとは

M3Uファイルは、どのようにTSファイルを再生していくかという情報が書かれているプレイリストです。
しかし、メディア全体のプレイリストではなく、メディアの一部のTSファイルのプレイリストであり、再生されるにつれてどんどん更新されていきます。
これによって、ライブストリーミングも行えるというわけです。
以下がM3Uファイルの例です。ただのプレーンテキストです。

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:18
#EXTINF:10.500000,
output_0000.ts
#EXTINF:12.625000,
output_0001.ts
#EXTINF:10.416667,
output_0002.ts
#EXTINF:10.416667,
output_0003.ts
// skip
output_0058.ts
#EXTINF:5.125000,
output_0059.ts
#EXT-X-ENDLIST

#EXT-X-MEDIA-SEQUENCE:0の部分はこのM3Uの先頭のTSファイルがメディア全体の何番目であるか、#EXT-X-TARGETDURATION:18の部分はそれぞれのTSファイルが何秒以下になるように分割されているか、#EXTINF:10.500000の部分は直下に参照されているTSファイルが何秒のものであるのか、がそれぞれ記録されています。
また、#EXT-X-TARGETDURATION:で表現された時間の0.5-1.5倍の時間間隔でM3Uファイルが更新されていきます。
つまり、ブラウザは、「M3Uファイルを取得して、それに従ってTSファイルを再生しながら、M3Uファイルを更新する」というサイクルを繰り返してストリーミングを実現しています。

MPEG-DASH

MPEG-DASHとは

MPEG-DASHはDASH-Industry Forumによって開発されたストリーミングプロトコルで、DASH-Industry ForumにはMicrosoft、Netflix、Google、Ericsson、Samsung、Adobeなどが参加しています。
ISOの規格としてリリースされています。
こちらもHLS同様、HTTPに基づいた通信を行うため、普通のweb server (nginxとかApache)を用いてマルチディアを配布できてしまう上、firewallなども問題になりません。
また、MPEG-DASHもメディアセグメントと、プレイリストによってストリーミングを行います。
MPEG-DASHでもセグメントはFragmented MP4形式もしくはMPEG-2 TS形式、プレイリストはMPD (Media Presentation Description)という形式のXMLファイル(拡張子は.mpd)で表現されます。

MPDとは

以下がMPDファイルの例です。こいつはxmlファイルです。

<?xml version="1.0"?>
<!-- MPD file Generated with GPAC version 0.6.1-revrelease  at 2016-09-29T12:57:43.136Z-->
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" minBufferTime="PT1.500S" type="static" mediaPresentationDuration="PT0H9M56.466S" maxSegmentDuration="PT0H0M4.000S" profiles="urn:mpeg:dash:profile:full:2011">
 <ProgramInformation moreInformationURL="http://gpac.sourceforge.net">
  <Title>./output.mpd generated by GPAC</Title>
 </ProgramInformation>
 <Period duration="PT0H9M56.466S">
  <AdaptationSet segmentAlignment="true" maxWidth="320" maxHeight="180" maxFrameRate="30" par="16:9" lang="und">
   <ContentComponent id="1" contentType="video" />
   <ContentComponent id="2" contentType="audio" />
   <Representation id="1" mimeType="video/mp4" codecs="avc3.640014,mp4a.40.2" width="320" height="180" frameRate="30" sar="1:1" audioSamplingRate="48000" startWithSAP="1" bandwidth="631708">
    <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
    <SegmentList timescale="1000" duration="4000">
     <Initialization sourceURL="outputinit.mp4"/>
     <SegmentURL media="output1.m4s"/>
     <SegmentURL media="output2.m4s"/>
     <SegmentURL media="output3.m4s"/>
     // skip
     <SegmentURL media="output149.m4s"/>
     <SegmentURL media="output150.m4s"/>
    </SegmentList>
   </Representation>
  </AdaptationSet>
 </Period>
</MPD>

Discussion