(Halos) walang kwentang webcam streaming mula sa isang browser. Media Stream at Websockets

Sa artikulong ito gusto kong ibahagi ang aking mga pagtatangka na mag-stream ng video sa pamamagitan ng mga websocket nang hindi gumagamit ng mga third-party na plugin ng browser gaya ng Adobe Flash Player. Magbasa para malaman kung ano ang nagmula rito.

Ang Adobe Flash, dating Macromedia Flash, ay isang platform para sa paglikha ng mga application na tumatakbo sa isang web browser. Bago ang pagpapakilala ng Media Stream API, ito ay halos ang tanging platform para sa streaming ng video at boses mula sa isang webcam, pati na rin para sa paglikha ng iba't ibang uri ng mga kumperensya at chat sa browser. Ang protocol para sa pagpapadala ng impormasyon ng media RTMP (Real Time Messaging Protocol) ay talagang sarado nang mahabang panahon, na nangangahulugang: kung gusto mong palakasin ang iyong streaming service, maging mabait na gumamit ng software mula sa Adobe mismo - Adobe Media Server (AMS).

Pagkaraan ng ilang oras noong 2012, "sumuko at iniluwa" ng Adobe sa publiko. pagtutukoy RTMP protocol, na naglalaman ng mga error at talagang hindi kumpleto. Sa oras na iyon, nagsimula ang mga developer na gumawa ng sarili nilang mga pagpapatupad ng protocol na ito, at lumitaw ang Wowza server. Noong 2011, nagsampa ng kaso ang Adobe laban sa Wowza para sa iligal na paggamit ng mga patent na nauugnay sa RTMP; pagkalipas ng 4 na taon, maayos na nalutas ang salungatan.

Ang platform ng Adobe Flash ay higit sa 20 taong gulang, kung saan maraming kritikal na kahinaan ang natuklasan, suporta nangako magtatapos sa 2020, nag-iiwan ng ilang mga alternatibo para sa serbisyo ng streaming.

Para sa aking proyekto, agad akong nagpasya na ganap na iwanan ang paggamit ng Flash sa browser. Ipinahiwatig ko ang pangunahing dahilan sa itaas; Hindi rin sinusuportahan ang Flash sa lahat ng mga mobile platform, at talagang ayaw kong mag-deploy ng Adobe Flash para sa pag-unlad sa Windows (wine emulator). Kaya nagtakda akong magsulat ng isang kliyente sa JavaScript. Ito ay magiging isang prototype lamang, dahil sa kalaunan ay nalaman ko na ang streaming ay maaaring gawin nang mas mahusay batay sa p2p, para sa akin lamang ito ay magiging peer - server - peer, ngunit higit pa sa ibang pagkakataon, dahil hindi pa ito handa.

Upang makapagsimula, kailangan namin ang aktwal na websockets server. Ginawa ko ang pinakasimpleng isa batay sa melody go package:

Code ng server

package main

import (
	"errors"
	"github.com/go-chi/chi"
	"gopkg.in/olahol/melody.v1"
	"log"
	"net/http"
	"time"
)

func main() {
	r := chi.NewRouter()
	m := melody.New()

	m.Config.MaxMessageSize = 204800

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, "public/index.html")
	})
	r.Get("/ws", func(w http.ResponseWriter, r *http.Request) {
		m.HandleRequest(w, r)
	})

         // Бродкастим Π²ΠΈΠ΄Π΅ΠΎ ΠΏΠΎΡ‚ΠΎΠΊ 
	m.HandleMessageBinary(func(s *melody.Session, msg []byte) {
		m.BroadcastBinary(msg)
	})

	log.Println("Starting server...")

	http.ListenAndServe(":3000", r)
}

Sa client (streaming side), kailangan mo munang i-access ang camera. Ginagawa ito sa pamamagitan ng MediaStream API.

Nagkakaroon kami ng access (pahintulot) sa camera/microphone sa pamamagitan ng Media Devices API. Nagbibigay ang API na ito ng paraan MediaDevices.getUserMedia(), na nagpapakita ng popup. isang window na humihingi ng pahintulot sa user na i-access ang camera at/o mikropono. Gusto kong tandaan na isinagawa ko ang lahat ng mga eksperimento sa Google Chrome, ngunit sa palagay ko lahat ay gagana nang pareho sa Firefox.

Susunod, ang getUserMedia() ay nagbabalik ng isang Pangako, kung saan ipinapasa nito ang isang MediaStream object - isang stream ng data ng video-audio. Itinalaga namin ang bagay na ito sa src property ng elemento ng video. Code:

Gilid ng pagsasahimpapawid

<style>
  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }
</style>
</head>
<body>
<!-- Π—Π΄Π΅ΡΡŒ Π² этом "ΠΎΠΊΠΎΡˆΠ΅Ρ‡ΠΊΠ΅" ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ сСбя -->
<video autoplay id="videoObjectHtml5ApiServer"></video>

<script type="application/javascript">
  var
        video = document.getElementById('videoObjectHtml5ApiServer');

// Ссли доступСн MediaDevices API, пытаСмся ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ ΠΊΠ°ΠΌΠ΅Ρ€Π΅ (ΠΌΠΎΠΆΠ½ΠΎ Π΅Ρ‰Π΅ ΠΈ ΠΊ ΠΌΠΈΠΊΡ€ΠΎΡ„ΠΎΠ½Ρƒ)
// getUserMedia Π²Π΅Ρ€Π½Π΅Ρ‚ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ подписываСмся ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹ΠΉ Π²ΠΈΠ΄Π΅ΠΎΠΏΠΎΡ‚ΠΎΠΊ Π² ΠΊΠΎΠ»Π±Π΅ΠΊΠ΅ направляСм Π² video ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π½Π° страницС

if (navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices.getUserMedia({video: true}).then(function (stream) {
          // Π²ΠΈΠ΄Π΅ΠΎ ΠΏΠΎΡ‚ΠΎΠΊ привязываСм ΠΊ video Ρ‚Π΅Π³Ρƒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ ΠΌΠΎΠ³ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ сСбя ΠΈ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ 
          video.srcObject = stream;
        });
}
</script>

Upang mag-broadcast ng video stream sa mga socket, kailangan mong i-encode ito sa isang lugar, i-buffer ito, at ipadala ito sa mga bahagi. Ang raw na video stream ay hindi maipapadala sa pamamagitan ng mga websocket. Ito ay kung saan ito ay dumating sa aming tulong MediaRecorder API. Binibigyang-daan ka ng API na ito na i-encode at hatiin ang stream sa mga piraso. Gumagawa ako ng pag-encode upang i-compress ang video stream upang magpadala ng mas kaunting mga byte sa network. Kapag nahati ito sa mga piraso, maaari mong ipadala ang bawat piraso sa isang websocket. Code:

Ini-encode namin ang video stream, pinaghiwa-hiwalay ito

<style>
  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }
</style>
</head>
<body>
<!-- Π—Π΄Π΅ΡΡŒ Π² этом "ΠΎΠΊΠΎΡˆΠ΅Ρ‡ΠΊΠ΅" ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ сСбя -->
<video autoplay id="videoObjectHtml5ApiServer"></video>

<script type="application/javascript">
  var
        video = document.getElementById('videoObjectHtml5ApiServer');

// Ссли доступСн MediaDevices API, пытаСмся ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ ΠΊΠ°ΠΌΠ΅Ρ€Π΅ (ΠΌΠΎΠΆΠ½ΠΎ Π΅Ρ‰Π΅ ΠΈ ΠΊ ΠΌΠΈΠΊΡ€ΠΎΡ„ΠΎΠ½Ρƒ)
// getUserMedia Π²Π΅Ρ€Π½Π΅Ρ‚ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ подписываСмся ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹ΠΉ Π²ΠΈΠ΄Π΅ΠΎΠΏΠΎΡ‚ΠΎΠΊ Π² ΠΊΠΎΠ»Π±Π΅ΠΊΠ΅ направляСм Π² video ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π½Π° страницС

if (navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices.getUserMedia({video: true}).then(function (stream) {
          // Π²ΠΈΠ΄Π΅ΠΎ ΠΏΠΎΡ‚ΠΎΠΊ привязываСм ΠΊ video Ρ‚Π΅Π³Ρƒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ ΠΌΠΎΠ³ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ сСбя ΠΈ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ 
          video.srcObject = s;
          var
            recorderOptions = {
                mimeType: 'video/webm; codecs=vp8' // Π±ΡƒΠ΄Π΅ΠΌ ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎΠΏΠΎΡ‚ΠΎΠΊ Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ webm ΠΊΠΎΠ΄Π΅ΠΊΠΎΠΌ vp8
              },
              mediaRecorder = new MediaRecorder(s, recorderOptions ); // ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ MediaRecorder

               mediaRecorder.ondataavailable = function(e) {
                if (e.data && e.data.size > 0) {
                  // ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ кусочСк Π²ΠΈΠ΄Π΅ΠΎΠΏΠΎΡ‚ΠΎΠΊΠ° Π² e.data
                }
            }

            mediaRecorder.start(100); // Π΄Π΅Π»ΠΈΡ‚ ΠΏΠΎΡ‚ΠΎΠΊ Π½Π° кусочки ΠΏΠΎ 100 мс ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ

        });
}
</script>

Ngayon, magdagdag tayo ng transmission sa pamamagitan ng mga websocket. Nakakagulat, ang kailangan mo lang para dito ay isang bagay WebSocket. Mayroon lamang itong dalawang paraan ng pagpapadala at pagsasara. Ang mga pangalan ay nagsasalita para sa kanilang sarili. Idinagdag na code:

Ipinapadala namin ang video stream sa server

<style>
  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }
</style>
</head>
<body>
<!-- Π—Π΄Π΅ΡΡŒ Π² этом "ΠΎΠΊΠΎΡˆΠ΅Ρ‡ΠΊΠ΅" ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ сСбя -->
<video autoplay id="videoObjectHtml5ApiServer"></video>

<script type="application/javascript">
  var
        video = document.getElementById('videoObjectHtml5ApiServer');

// Ссли доступСн MediaDevices API, пытаСмся ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ ΠΊΠ°ΠΌΠ΅Ρ€Π΅ (ΠΌΠΎΠΆΠ½ΠΎ Π΅Ρ‰Π΅ ΠΈ ΠΊ ΠΌΠΈΠΊΡ€ΠΎΡ„ΠΎΠ½Ρƒ)
// getUserMedia Π²Π΅Ρ€Π½Π΅Ρ‚ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ подписываСмся ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹ΠΉ Π²ΠΈΠ΄Π΅ΠΎΠΏΠΎΡ‚ΠΎΠΊ Π² ΠΊΠΎΠ»Π±Π΅ΠΊΠ΅ направляСм Π² video ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π½Π° страницС

if (navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices.getUserMedia({video: true}).then(function (stream) {
          // Π²ΠΈΠ΄Π΅ΠΎ ΠΏΠΎΡ‚ΠΎΠΊ привязываСм ΠΊ video Ρ‚Π΅Π³Ρƒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ ΠΌΠΎΠ³ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ сСбя ΠΈ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ 
          video.srcObject = s;
          var
            recorderOptions = {
                mimeType: 'video/webm; codecs=vp8' // Π±ΡƒΠ΄Π΅ΠΌ ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎΠΏΠΎΡ‚ΠΎΠΊ Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ webm ΠΊΠΎΠ΄Π΅ΠΊΠΎΠΌ vp8
              },
              mediaRecorder = new MediaRecorder(s, recorderOptions ), // ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ MediaRecorder
              socket = new WebSocket('ws://127.0.0.1:3000/ws');

               mediaRecorder.ondataavailable = function(e) {
                if (e.data && e.data.size > 0) {
                  // ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ кусочСк Π²ΠΈΠ΄Π΅ΠΎΠΏΠΎΡ‚ΠΎΠΊΠ° Π² e.data
                 socket.send(e.data);
                }
            }

            mediaRecorder.start(100); // Π΄Π΅Π»ΠΈΡ‚ ΠΏΠΎΡ‚ΠΎΠΊ Π½Π° кусочки ΠΏΠΎ 100 мс ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ

        }).catch(function (err) { console.log(err); });
}
</script>

Handa na ang broadcast side! Ngayon subukan nating makatanggap ng video stream at ipakita ito sa kliyente. Ano ang kailangan natin para dito? Una, siyempre, ang koneksyon sa socket. Nag-attach kami ng "tagapakinig" sa object ng WebSocket at nag-subscribe sa kaganapang 'mensahe'. Ang pagkakaroon ng nakatanggap ng isang piraso ng binary data, ang aming server ay nag-broadcast nito sa mga subscriber, iyon ay, mga kliyente. Sa kasong ito, ang callback function na nauugnay sa "tagapakinig" ng 'mensahe' na kaganapan ay na-trigger sa client; ang object mismo ay ipinapasa sa argument ng function - isang piraso ng video stream na na-encode ng vp8.

Tumatanggap kami ng video stream

<style>
  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }
</style>
</head>
<body>
<!-- Π—Π΄Π΅ΡΡŒ Π² этом "ΠΎΠΊΠΎΡˆΠ΅Ρ‡ΠΊΠ΅" ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ тСбя -->
<video autoplay id="videoObjectHtml5ApiServer"></video>

<script type="application/javascript">
  var
        video = document.getElementById('videoObjectHtml5ApiServer'),
         socket = new WebSocket('ws://127.0.0.1:3000/ws'), 
         arrayOfBlobs = [];

         socket.addEventListener('message', function (event) {
                // "ΠΊΠ»Π°Π΄Π΅ΠΌ" ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹ΠΉ кусочСк Π² массив 
                arrayOfBlobs.push(event.data);
                // здСсь Π±ΡƒΠ΄Π΅ΠΌ Ρ‡ΠΈΡ‚Π°Ρ‚ΡŒ кусочки
                readChunk();
            });
</script>

Sa loob ng mahabang panahon sinubukan kong maunawaan kung bakit imposibleng agad na ipadala ang mga natanggap na piraso sa elemento ng video para sa pag-playback, ngunit ito ay hindi maaaring gawin, siyempre, kailangan mo munang ilagay ang piraso sa isang espesyal na buffer na nakatali sa ang elemento ng video, at saka lang ito magsisimulang mag-play ng video stream. Para dito kakailanganin mo MediaSource API ΠΈ FileReader API.

Gumaganap ang MediaSource bilang isang uri ng tagapamagitan sa pagitan ng object ng pag-playback ng media at ang pinagmulan ng media stream na ito. Ang MediaSource object ay naglalaman ng isang pluggable buffer para sa pinagmulan ng video/audio stream. Ang isang tampok ay ang buffer ay maaari lamang humawak ng data ng Uint8, kaya kakailanganin mo ng isang FileReader upang lumikha ng gayong buffer. Tingnan ang code at ito ay magiging mas malinaw:

Nagpe-play ng video stream

<style>
  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }
</style>
</head>
<body>
<!-- Π—Π΄Π΅ΡΡŒ Π² этом "ΠΎΠΊΠΎΡˆΠ΅Ρ‡ΠΊΠ΅" ΠΊΠ»ΠΈΠ΅Π½Ρ‚ Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ тСбя -->
<video autoplay id="videoObjectHtml5ApiServer"></video>

<script type="application/javascript">
  var
        video = document.getElementById('videoObjectHtml5ApiServer'),
         socket = new WebSocket('ws://127.0.0.1:3000/ws'),
        mediaSource = new MediaSource(), // ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ MediaSource
        vid2url = URL.createObjectURL(mediaSource), // создаСм ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ URL для связывания Π²ΠΈΠ΄Π΅ΠΎΠΏΠΎΡ‚ΠΎΠΊΠ° с ΠΏΡ€ΠΎΠΈΠ³Ρ€Ρ‹Π²Π°Ρ‚Π΅Π»Π΅ΠΌ
        arrayOfBlobs = [],
        sourceBuffer = null; // Π±ΡƒΡ„Π΅Ρ€, ΠΏΠΎΠΊΠ° Π½ΡƒΠ»ΡŒ-ΠΎΠ±ΡŠΠ΅ΠΊΡ‚

         socket.addEventListener('message', function (event) {
                // "ΠΊΠ»Π°Π΄Π΅ΠΌ" ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹ΠΉ кусочСк Π² массив 
                arrayOfBlobs.push(event.data);
                // здСсь Π±ΡƒΠ΄Π΅ΠΌ Ρ‡ΠΈΡ‚Π°Ρ‚ΡŒ кусочки
                readChunk();
            });

         // ΠΊΠ°ΠΊ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ MediaSource Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠΏΠΎΠ²Π΅Ρ‰Π΅Π½ , Ρ‡Ρ‚ΠΎ источник Π³ΠΎΡ‚ΠΎΠ² ΠΎΡ‚Π΄Π°Π²Π°Ρ‚ΡŒ кусочки 
        // Π²ΠΈΠ΄Π΅ΠΎ/Π°ΡƒΠ΄ΠΈΠΎ ΠΏΠΎΡ‚ΠΎΠΊΠ°
        // создаСм Π±ΡƒΡ„Π΅Ρ€ , слСдуСт ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, Ρ‡Ρ‚ΠΎ Π±ΡƒΡ„Π΅Ρ€ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π·Π½Π°Ρ‚ΡŒ Π² ΠΊΠ°ΠΊΠΎΠΌ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ 
        // ΠΊΠ°ΠΊΠΈΠΌ ΠΊΠΎΠ΄Π΅ΠΊΠΎΠΌ Π±Ρ‹Π» Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½ ΠΏΠΎΡ‚ΠΎΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρ‚Π΅ΠΌ ΠΆΠ΅ способом ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ Π²ΠΈΠ΄Π΅ΠΎΠΏΠΎΡ‚ΠΎΠΊ
         mediaSource.addEventListener('sourceopen', function() {
            var mediaSource = this;
            sourceBuffer = mediaSource.addSourceBuffer("video/webm; codecs="vp8"");
        });

      function readChunk() {
        var reader = new FileReader();
        reader.onload = function(e) { 
          // ΠΊΠ°ΠΊ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ FileReader Π±ΡƒΠ΄Π΅Ρ‚ Π³ΠΎΡ‚ΠΎΠ², ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ сСбС кусочСк Π²ΠΈΠ΄Π΅ΠΎΠΏΠΎΡ‚ΠΎΠΊΠ°
          // ΠΌΡ‹ "прицСпляСм" ΠΏΠ΅Ρ€Π΅ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ Π² Uint8Array (Π±Ρ‹Π» Blob) кусочСк Π² Π±ΡƒΡ„Π΅Ρ€, связанный
          // с ΠΏΡ€ΠΎΠΈΠ³Ρ€Ρ‹Π²Π°Ρ‚Π΅Π»Π΅ΠΌ, ΠΈ ΠΏΡ€ΠΎΠΈΠ³Ρ€Ρ‹Π²Π°Ρ‚Π΅Π»ΡŒ Π½Π°Ρ‡ΠΈΠ½Π°Π΅Ρ‚ Π²ΠΎΡΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹ΠΉ кусочСк Π²ΠΈΠ΄Π΅ΠΎ/Π°ΡƒΠ΄ΠΈΠΎ
          sourceBuffer.appendBuffer(new Uint8Array(e.target.result));

          reader.onload = null;
        }
        reader.readAsArrayBuffer(arrayOfBlobs.shift());
      }
</script>

Ang prototype ng streaming service ay handa na. Ang pangunahing kawalan ay ang pag-playback ng video ay mahuhuli sa gilid ng pagpapadala ng 100 ms; itinakda namin ito mismo kapag hinahati ang stream ng video bago ito ipadala sa server. Bukod dito, nang suriin ko ang aking laptop, ang lag sa pagitan ng mga panig ng pagpapadala at pagtanggap ay unti-unting naipon, ito ay malinaw na nakikita. Nagsimula akong maghanap ng mga paraan upang malampasan ang kawalan na ito, at... napunta ako RTCPeerConnection API, na nagbibigay-daan sa iyong magpadala ng video stream nang walang mga trick gaya ng paghahati-hati ng stream sa mga piraso. Ang naipon na lag, sa tingin ko, ay dahil sa ang katunayan na ang browser ay muling nag-encode ng bawat piraso sa webm na format bago ang paghahatid. Hindi na ako naghukay pa, ngunit nagsimulang mag-aral ng WebRTC. Sa palagay ko ay magsusulat ako ng isang hiwalay na artikulo tungkol sa mga resulta ng aking pananaliksik kung sa tingin ko ay kawili-wili ito sa komunidad.

Pinagmulan: www.habr.com

Magdagdag ng komento