Auteur | Liu Bo (également ingénieur de développement multimédia Paiyun)
Actuellement, afin de répondre à la demande relativement forte de diffusion en direct sur le Web mobile, une série de technologies de diffusion en direct HTML5 ont été rapidement développées.
Les technologies de diffusion en direct courantes pouvant être utilisées avec HTML5 incluent HLS, WebSocket et WebRTC. Aujourd'hui je vais vous présenter les points techniques liés à WebSocket et MSE, et enfin vous démontrer l'utilisation spécifique à travers un exemple.
Introduction au protocole WebSocket
Introduction à l'API client/serveur WebSocket
Introduction à MSE
Introduction à fMP4
Affichage de la démonstration
Les applications Web habituelles sont construites autour du modèle de requête/réponse HTTP. Toutes les communications HTTP sont contrôlées via le client. Le client envoie une requête au serveur une fois que le serveur l'a reçue et traitée, il renvoie le résultat au client et le client affiche les données. Comme ce mode ne peut pas répondre aux besoins des applications temps réel, des technologies de connexion longue « poussée par le serveur » telles que SSE et Comet ont vu le jour.
WebSocket est un protocole de communication basé sur une connexion TCP, qui peut effectuer une communication full-duplex sur une seule connexion TCP. WebSocket a été défini comme norme RFC 6455 par l'IETF en 2011 et complété par la RFC 7936. L'API WebSocket a été définie comme norme par le W3C.
WebSocket est un protocole créé indépendamment sur TCP. Les concepts du protocole HTTP ne sont pas liés à WebSocket. La seule corrélation est que lors de l'utilisation du code d'état 101 du protocole HTTP pour la commutation de protocole, le port TCP utilisé. est de 80, ce qui permet de contourner la plupart des restrictions du pare-feu.
Afin de déployer plus facilement de nouveaux protocoles, HTTP/1.1 introduit le mécanisme de mise à niveau, permettant au client et au serveur d'utiliser certains protocoles HTTP existants. la syntaxe est mise à niveau vers d’autres protocoles. Ce mécanisme est décrit en détail dans la RFC7230, section 6.7 Mise à niveau.
Pour lancer une mise à niveau du protocole HTTP/1.1, le client doit préciser ces deux champs dans l'en-tête de la requête ▽
> Connection: Upgrade Upgrade: protocol-name[/protocol-version]
Si le serveur accepte la mise à niveau , alors vous devez répondre comme ceci ▽
> HTTP/1.1 101 Switching Protocols Connection: upgrade Upgrade: protocol-name[/protocol-version] [... data defined by new protocol ...]
Comme vous pouvez le voir, le code d'état de la réponse HTTP Upgrade est 101, et le corps de la réponse peut être défini à l’aide du nouveau format de données du protocole.
La poignée de main WebSocket profite de ce mécanisme de mise à niveau HTTP. Une fois la négociation terminée, le transfert de données ultérieur s'effectue directement via TCP.
Actuellement, les navigateurs grand public fournissent une interface API WebSocket, qui peut envoyer des messages (texte ou binaire) au serveur et recevoir des données de réponse basées sur des événements.
Étape 1. Vérifiez si le navigateur prend en charge WebSocket
> if(window.WebSocket) { // WebSocket代码 }
Établissez une connexion
> var ws = new WebSocket('ws://localhost:8327');
Étape 3. Enregistrez les fonctions de rappel et envoyez et recevez des données
Enregistrez respectivement les fonctions de rappel onopen, onclose, onerror et onmessage de l'objet WebSocket.
Envoyer des données via ws.send(). Non seulement des chaînes peuvent être envoyées ici, mais également des données de type Blob ou ArrayBuffer.
Si des données binaires sont reçues, le format de l'objet de connexion doit être défini sur blob ou arraybuffer.
ws.binaryType = 'arraybuffer';
API WebSocket Golang
Pour la bibliothèque WebSocket côté serveur, je recommande d'utiliser le http://golang.org/x/net/websocket de Google, qui est très pratique Utilisé avec net/http. Vous pouvez également convertir la fonction de gestionnaire de WebSocket en http.Handler via websocket.Handler, afin qu'elle puisse être utilisée avec la bibliothèque net/http.
Ensuite, recevez des données via websocket.Message.Receive et envoyez des données via websocket.Message.Send.
Le code spécifique peut être trouvé dans la section Démo ci-dessous.
Avant de présenter MSE, examinons d'abord les limites de HTML5
Limitations des balises HTML5
Le streaming n'est pas pris en charge
Le DRM et le cryptage sont non pris en charge
Difficile de personnaliser les contrôles et de maintenir la cohérence entre les navigateurs
La prise en charge du codage et de l'encapsulation est différente selon les navigateurs
MSE résout le problème de streaming du HTML5.
Media Source Extensions (MSE) est une nouvelle API Web prise en charge par les navigateurs grand public tels que Chrome, Safari et Edge. MSE est une norme du W3C qui permet à JavaScript de construire dynamiquement des flux multimédias pour les formats
En utilisant MSE, vous pouvez modifier dynamiquement les flux multimédias sans avoir besoin de plugins. Cela permet à JavaScript frontal de faire plus : reconditionnement, traitement et même transcodage en JavaScript.
Bien que MSE ne puisse pas transmettre de flux directement aux balises multimédias, MSE fournit la technologie de base pour créer des lecteurs multi-navigateurs, permettant aux navigateurs de transmettre l'audio et la vidéo aux balises multimédias via des API JavaScript.
Utilisez caniuse pour vérifier si la prise en charge du navigateur est disponible.
Vous pouvez également vérifier si le type de codec MIME est pris en charge via MediaSource.isTypeSupported().
Les formats d'encapsulation vidéo les plus couramment utilisés sont WebM et fMP4.
WebM et WebP sont deux projets frères, tous deux sponsorisés par Google. Puisque WebM est un format de conteneur basé sur Matroska, il est intrinsèquement en streaming et est très approprié pour une utilisation dans le domaine du streaming multimédia.
Ce qui suit se concentre sur le format fMP4.
Nous savons tous que MP4 est composé d'une série de Box. Le MP4 ordinaire a une structure imbriquée. Le client doit charger un fichier MP4 depuis le début avant de pouvoir le lire complètement, et il ne peut pas commencer la lecture à partir de la section centrale.
Et fMP4 se compose d'une série de fragments. Si le serveur prend en charge les requêtes de plage d'octets, ces fragments peuvent être demandés indépendamment au client pour la lecture sans charger l'intégralité du fichier.
Pour illustrer ce point de manière plus vivante, je présente ci-dessous plusieurs outils couramment utilisés pour analyser les fichiers MP4.
gpac, anciennement connu sous le nom de mp4box, est un framework de développement multimédia. Il existe un grand nombre d'outils d'analyse multimédia sous son code source, qui peuvent être utilisés dans les applications de test ; 🎜>mp4box.js, est la version Javascript de mp4box
bento4, un outil d'analyse spécifiquement pour MP4
mp4parser, un fichier MP4 en ligne ; outil d’analyse.
fragment mp4 VS non-fragment mp4
Apple a annoncé lors de la conférence WWDC 2016 qu'il prendrait en charge fMP4 dans HLS sous iOS 10, tvOS et macOS. On voit que les perspectives de fMP4 sont très bonnes.
Il convient de mentionner que fMP4, CMAF et ISOBMFF sont en fait des choses similaires.
API JavaScript MSE
À un niveau élevé, MSE fournit
un ensemble d'API JavaScript pour créer des flux multimédias
Un modèle d'assemblage et de mise en cache
Identifie certains types de flux d'octets
WebM
Format de fichier multimédia de base ISO
Flux de transport MPEG-2
Structure interne MSE
MSE 本身的设计是不依赖任务特定的编解码和容器格式的,但是不同的浏览器支持程度是不一样的。
可以通过传递一个 MIME 类型的字符串到静态方法:
> MediaSource.isTypeSupported来检查。比如 ▽ MediaSource.isTypeSupported('audio/mp3'); // false MediaSource.isTypeSupported('video/mp4'); // true MediaSource.isTypeSupported('video/mp4; codecs="avc1.4D4028, mp4a.40.2"'); // true
获取 Codec MIME string 的方法可以通过在线的 [mp4info](http://nickdesaulniers.github.io/mp4info),或者使用命令行 mp4info test.mp4 | grep Codecs,可以得到类似如下结果 ▽
> mp4info fmp4.mp4| grep Codec Codecs String: mp4a.40.2 Codecs String: avc1.42E01E
当前,H.264 + AAC 的 MP4 容器在所有的浏览器都支持。
普通的 MP4 文件是不能和 MSE 一起使用的, 需要将 MP4 进行 fragment 化。
检查一个 MP4 是否已经 fragment 的方法 ▽
> mp4dump test.mp4 | grep "\[m"
如果是non-fragment会显示如下信息 ▽
> mp4dump nfmp4.mp4 | grep "\[m" [mdat] size=8+50873 [moov] size=8+7804 [mvhd] size=12+96 [mdia] size=8+3335 [mdhd] size=12+20 [minf] size=8+3250 [mdia] size=8+3975 [mdhd] size=12+20 [minf] size=8+3890 [mp4a] size=8+82 [meta] size=12+78
如果已经 fragment,会显示如下的类似信息 ▽
> mp4dump fmp4.mp4 | grep "\[m" | head -n 30 [moov] size=8+1871 [mvhd] size=12+96 [mdia] size=8+312 [mdhd] size=12+20 [minf] size=8+219 [mp4a] size=8+67 [mdia] size=8+371 [mdhd] size=12+20 [minf] size=8+278 [mdia] size=8+248 [mdhd] size=12+20 [minf] size=8+156 [mdia] size=8+248 [mdhd] size=12+20 [minf] size=8+156 [mvex] size=8+144 [mehd] size=12+4 [moof] size=8+600 [mfhd] size=12+4 [mdat] size=8+138679 [moof] size=8+536 [mfhd] size=12+4 [mdat] size=8+24490 [moof] size=8+592 [mfhd] size=12+4 [mdat] size=8+14444 [moof] size=8+312 [mfhd] size=12+4 [mdat] size=8+1840 [moof] size=8+600
把一个 non-fragment MP4 转换成 fragment MP4。
可以使用 FFmpeg 的 -movflags 来转换。
对于原始文件为非 MP4 文件 ▽
> ffmpeg -i trailer_1080p.mov -c:v copy -c:a copy -movflags frag_keyframe+empty_moov bunny_fragmented.mp4
对于原始文件已经是 MP4 文件 ▽
> ffmpeg -i non_fragmented.mp4 -movflags frag_keyframe+empty_moov fragmented.mp4
或者使用 mp4fragment ▽
> mp4fragment input.mp4 output.mp4
DEMO TIME
最后阶段,展示两个demo,分别是 MSE Vod Demo、MSE Live Demo
MSE Vod Demo
展示利用 MSE 和 WebSocket 实现一个点播服务
后端读取一个 fMP4 文件,通过 WebSocket 发送给 MSE,进行播放
展示利用 MSE 和 WebSocket 实现一个直播服务
后端代理一条 HTTP-FLV 直播流,通过 WebSocket 发送给 MSE,进行播放
前端 MSE 部分做了很多工作, 包括将 flv 实时转封装成了 fMP4,这里引用了 videojs-flow 的实现
Refs
WebSocket
rfc6455
HTTP Upgrade
WebSocket API
MDN WebSocket
videojs-flow
MSE
W3C
MDN MSE
HTML5 Codec MIME
又拍直播云是基于又拍云内容分发网络为直播应用提供超低延迟、高码率、高并发的整套从推流端到播放端的一站式解决方案。包括实时转码,实时录制,分发加速,水印,截图,秒级禁播,延时直播等功能。直播源站支持自主源站或又拍云源,为支持用户在不同终端播放,支持 RTMP、HLS、HTTP-flv 播放输出。
详情了解:https://www.upyun.com/products/live
推荐阅读:
无连麦,不直播,都在说的直播利器连麦互动到底是啥?
技术干货|移动直播六大关键技术详解
又拍直播云SDK,自带美颜、滤镜、消噪、人声增益等功能
又拍直播云功能处理篇:转码、录制、视频水印、视频截图
又拍直播云功能基础篇:推流和拉流、多协议输出、多访问方式、回源端口自定义
又拍直播云功能高级篇:防盗链、秒级禁播、自动鉴黄、API接口
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!