{"id":94138,"date":"2020-09-13T07:42:42","date_gmt":"2020-09-13T05:42:42","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/pochti-bespoleznyj-striming-vebkamery-iz-brauzera-media-stream-i-websockets"},"modified":"2020-09-13T07:42:42","modified_gmt":"2020-09-13T05:42:42","slug":"pochti-bespoleznyj-striming-vebkamery-iz-brauzera-media-stream-i-websockets","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/pochti-bespoleznyj-striming-vebkamery-iz-brauzera-media-stream-i-websockets","title":{"rendered":"(Fast) nutzloses Streaming von Webcam \u00fcber den Browser. Media Stream und Websockets","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>In diesem Artikel m\u00f6chte ich meine Versuche teilen, Video-Streaming \u00fcber Websockets ohne die Verwendung von Drittanbieter-Browser-Plugins wie Adobe Flash Player zu erm\u00f6glichen. Was dabei herausgekommen ist, lesen Sie weiter.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><br \/>\nAdobe Flash \u2013 fr\u00fcher Macromedia Flash \u2013 ist eine Plattform zur Erstellung von Anwendungen, die im Webbrowser funktionieren. Bis zur Einf\u00fchrung der Media Stream API war dies praktisch die einzige Plattform f\u00fcr Webcam-Streaming von Video und Ton sowie f\u00fcr die Erstellung von Konferenzen und Chats im Browser. Protokoll f\u00fcr die \u00dcbertragung von Medieninformationen ist RTMP (Real Time Messaging Protocol), das lange Zeit faktisch geschlossen war, was bedeutete: Wenn Sie Ihren Streaming-Service aufbauen wollten, mussten Sie die Software von Adobe selbst verwenden \u2013 Adobe Media Server (AMS). <\/p>\n<p>Nach einiger Zeit, im Jahr 2012, gab Adobe \u201eauf und pr\u00e4sentierte\u201c der \u00d6ffentlichkeit <noindex><a rel=\"nofollow\" href=\"http:\/\/wwwimages.adobe.com\/www.adobe.com\/content\/dam\/acom\/en\/devnet\/rtmp\/pdf\/rtmp_specification_1.0.pdf\">die Spezifikation<\/a><\/noindex> des RTMP-Protokolls, die Fehler enthielt und im Grunde genommen unvollst\u00e4ndig war. Zu diesem Zeitpunkt begannen Entwickler, ihre eigenen Implementierungen dieses Protokolls zu erstellen, so entstand der Wowza-Server. Im Jahr 2011 reichte Adobe eine Klage gegen Wowza wegen unrechtm\u00e4\u00dfiger Nutzung von mit RTMP verbundenen Patenten ein, vier Jahre sp\u00e4ter wurde der Konflikt friedlich gel\u00f6st. <\/p>\n<p>Adobe Flash ist seit \u00fcber 20 Jahren auf dem Markt und hat in dieser Zeit zahlreiche kritische Sicherheitsanf\u00e4lligkeiten aufgezeigt. Die Unterst\u00fctzung <noindex><a rel=\"nofollow\" href=\"https:\/\/webkit.org\/blog\/7839\/adobe-announces-flash-distribution-and-updates-to-end\/\">wurde<\/a><\/noindex> versprochen, bis 2020 eingestellt zu werden, sodass es nicht viele Alternativen f\u00fcr Streaming-Dienste gibt. <\/p>\n<p>F\u00fcr mein Projekt habe ich mich sofort entschieden, komplett auf Flash im Browser zu verzichten. Die Hauptgr\u00fcnde habe ich oben bereits genannt; zudem wird Flash auf mobilen Plattformen gar nicht unterst\u00fctzt und es war mir auch nicht recht, Adobe Flash unter Windows (im Wine-Emulator) einzusetzen. Daher habe ich damit begonnen, einen Client in JavaScript zu schreiben. Dies wird nur ein Prototyp sein, da ich sp\u00e4ter erfahren habe, dass Streaming auf Basis von P2P viel effizienter gestaltet werden kann. Dabei werde ich ein Peer-Server-Peers-Modell verwenden, aber dazu sp\u00e4ter mehr, da dies noch nicht fertig ist.<\/p>\n<p>Zun\u00e4chst ben\u00f6tigen wir einen eigenen WebSockets-Server. Ich habe einen sehr einfachen auf Basis des Go-Pakets melody erstellt:<\/p>\n<p>                        <b class=\"spoiler_title\">Server-Code<\/b><\/p>\n<pre><code class=\"go\">package main\n\nimport (\n\t&quot;errors&quot;\n\t&quot;github.com\/go-chi\/chi&quot;\n\t&quot;gopkg.in\/olahol\/melody.v1&quot;\n\t&quot;log&quot;\n\t&quot;net\/http&quot;\n\t&quot;time&quot;\n)\n\nfunc main() {\n\tr := chi.NewRouter()\n\tm := melody.New()\n\n\tm.Config.MaxMessageSize = 204800\n\n\tr.Get(&quot;\/&quot;, func(w http.ResponseWriter, r *http.Request) {\n\t\thttp.ServeFile(w, r, &quot;public\/index.html&quot;)\n\t})\n\tr.Get(&quot;\/ws&quot;, func(w http.ResponseWriter, r *http.Request) {\n\t\tm.HandleRequest(w, r)\n\t})\n\n         \/\/ \u0411\u0440\u043e\u0434\u043a\u0430\u0441\u0442\u0438\u043c \u0432\u0438\u0434\u0435\u043e \u043f\u043e\u0442\u043e\u043a \n\tm.HandleMessageBinary(func(s *melody.Session, msg []byte) {\n\t\tm.BroadcastBinary(msg)\n\t})\n\n\tlog.Println(&quot;Starting server...&quot;)\n\n\thttp.ListenAndServe(&quot;:3000&quot;, r)\n}\n<\/code><\/pre>\n<p>Auf der Client-Seite (Sender-Seite) muss zun\u00e4chst auf die Kamera zugegriffen werden. Dies geschieht \u00fcber <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Media_Streams_API\">MediaStream API<\/a><\/noindex>.<\/p>\n<p>Wir erhalten Zugriff (Erlaubnis) auf die Kamera\/den Mikrofon \u00fcber <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/MediaDevices\">Media Devices API<\/a><\/noindex>. Diese API bietet die Methode <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/MediaDevices\/getUserMedia\">MediaDevices.getUserMedia()<\/a><\/noindex>, die ein Popup-Fenster anzeigt und den Benutzer um Erlaubnis f\u00fcr den Zugriff auf die Kamera und\/oder das Mikrofon fragt. Ich m\u00f6chte bemerken, dass ich alle Experimente in Google Chrome durchgef\u00fchrt habe, aber ich denke, dass es in Firefox \u00e4hnlich funktionieren wird.<\/p>\n<p>Anschlie\u00dfend gibt getUserMedia() ein Promise zur\u00fcck, das ein MediaStream-Objekt \u2014 einen Video-Audio-Datenstrom \u2014 \u00fcbertr\u00e4gt. Dieses Objekt weisen wir der src-Eigenschaft des Video-Elements zu. Der Code:<\/p>\n<p>                        <b class=\"spoiler_title\">Die Sender-Seite<\/b><\/p>\n<pre><code class=\"javascript\">&lt;style&gt;\n  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }\n&lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;!-- \u0417\u0434\u0435\u0441\u044c \u0432 \u044d\u0442\u043e\u043c &quot;\u043e\u043a\u043e\u0448\u0435\u0447\u043a\u0435&quot; \u043a\u043b\u0438\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u0438\u0434\u0435\u0442\u044c \u0441\u0435\u0431\u044f --&gt;\n&lt;video autoplay id=&quot;videoObjectHtml5ApiServer&quot;&gt;&lt;\/video&gt;\n\n&lt;script type=&quot;application\/javascript&quot;&gt;\n  var\n        video = document.getElementById(&#039;videoObjectHtml5ApiServer&#039;);\n\n\/\/ \u0435\u0441\u043b\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d MediaDevices API, \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u0430\u043c\u0435\u0440\u0435 (\u043c\u043e\u0436\u043d\u043e \u0435\u0449\u0435 \u0438 \u043a \u043c\u0438\u043a\u0440\u043e\u0444\u043e\u043d\u0443)\n\/\/ getUserMedia \u0432\u0435\u0440\u043d\u0435\u0442 \u043e\u0431\u0435\u0449\u0430\u043d\u0438\u0435, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a \u0432 \u043a\u043e\u043b\u0431\u0435\u043a\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432 video \u043e\u0431\u044a\u0435\u043a\u0442 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435\n\nif (navigator.mediaDevices.getUserMedia) {\n        navigator.mediaDevices.getUserMedia({video: true}).then(function (stream) {\n          \/\/ \u0432\u0438\u0434\u0435\u043e \u043f\u043e\u0442\u043e\u043a \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u043a video \u0442\u0435\u0433\u0443, \u0447\u0442\u043e\u0431\u044b \u043a\u043b\u0438\u0435\u043d\u0442 \u043c\u043e\u0433 \u0432\u0438\u0434\u0435\u0442\u044c \u0441\u0435\u0431\u044f \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \n          video.srcObject = stream;\n        });\n}\n&lt;\/script&gt;\n<\/code><\/pre>\n<p>Um einen Video-Stream \u00fcber Sockets zu \u00fcbertragen, muss er in irgendeiner Weise kodiert, zwischengespeichert und in Teilen gesendet werden. Ein roher Video-Stream kann nicht \u00fcber Websockets \u00fcbertragen werden. Hier kommt uns <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/MediaStream_Recording_API\">das MediaRecorder API<\/a><\/noindex>zur Hilfe. Dieses API erm\u00f6glicht es, den Stream zu kodieren und in St\u00fccke zu zerlegen. Das Kodieren erfolgt zur Kompression des Video-Streams, um weniger Bytes \u00fcber das Netzwerk zu senden. Indem wir ihn in St\u00fccke zerlegen, kann jedes St\u00fcck in ein Websocket gesendet werden. Code:<\/p>\n<p>                        <b class=\"spoiler_title\">Wir kodieren den Video-Stream und zerteilen ihn<\/b><\/p>\n<pre><code class=\"javascript\">&lt;style&gt;\n  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }\n&lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;!-- \u0417\u0434\u0435\u0441\u044c \u0432 \u044d\u0442\u043e\u043c &quot;\u043e\u043a\u043e\u0448\u0435\u0447\u043a\u0435&quot; \u043a\u043b\u0438\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u0438\u0434\u0435\u0442\u044c \u0441\u0435\u0431\u044f --&gt;\n&lt;video autoplay id=&quot;videoObjectHtml5ApiServer&quot;&gt;&lt;\/video&gt;\n\n&lt;script type=&quot;application\/javascript&quot;&gt;\n  var\n        video = document.getElementById(&#039;videoObjectHtml5ApiServer&#039;);\n\n\/\/ \u0435\u0441\u043b\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d MediaDevices API, \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u0430\u043c\u0435\u0440\u0435 (\u043c\u043e\u0436\u043d\u043e \u0435\u0449\u0435 \u0438 \u043a \u043c\u0438\u043a\u0440\u043e\u0444\u043e\u043d\u0443)\n\/\/ getUserMedia \u0432\u0435\u0440\u043d\u0435\u0442 \u043e\u0431\u0435\u0449\u0430\u043d\u0438\u0435, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a \u0432 \u043a\u043e\u043b\u0431\u0435\u043a\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432 video \u043e\u0431\u044a\u0435\u043a\u0442 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435\n\nif (navigator.mediaDevices.getUserMedia) {\n        navigator.mediaDevices.getUserMedia({video: true}).then(function (stream) {\n          \/\/ \u0432\u0438\u0434\u0435\u043e \u043f\u043e\u0442\u043e\u043a \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u043a video \u0442\u0435\u0433\u0443, \u0447\u0442\u043e\u0431\u044b \u043a\u043b\u0438\u0435\u043d\u0442 \u043c\u043e\u0433 \u0432\u0438\u0434\u0435\u0442\u044c \u0441\u0435\u0431\u044f \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \n          video.srcObject = s;\n          var\n            recorderOptions = {\n                mimeType: &#039;video\/webm; codecs=vp8&#039; \/\/ \u0431\u0443\u0434\u0435\u043c \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a \u0432 \u0444\u043e\u0440\u043c\u0430\u0442 webm \u043a\u043e\u0434\u0435\u043a\u043e\u043c vp8\n              },\n              mediaRecorder = new MediaRecorder(s, recorderOptions ); \/\/ \u043e\u0431\u044a\u0435\u043a\u0442 MediaRecorder\n\n               mediaRecorder.ondataavailable = function(e) {\n                if (e.data &amp;&amp; e.data.size &gt; 0) {\n                  \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u0443\u0441\u043e\u0447\u0435\u043a \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a\u0430 \u0432 e.data\n                }\n            }\n\n            mediaRecorder.start(100); \/\/ \u0434\u0435\u043b\u0438\u0442 \u043f\u043e\u0442\u043e\u043a \u043d\u0430 \u043a\u0443\u0441\u043e\u0447\u043a\u0438 \u043f\u043e 100 \u043c\u0441 \u043a\u0430\u0436\u0434\u044b\u0439\n\n        });\n}\n&lt;\/script&gt;\n<\/code><\/pre>\n<p>Jetzt f\u00fcgen wir die \u00dcbertragung \u00fcber Websockets hinzu. \u00dcberraschenderweise ben\u00f6tigen wir daf\u00fcr nur ein Objekt <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/WebSocket\">WebSocket<\/a><\/noindex>. Es hat nur zwei Methoden: send und close. Die Namen sprechen f\u00fcr sich. Erg\u00e4nzter Code:<\/p>\n<p>                        <b class=\"spoiler_title\">Wir senden den Video-Stream an den Server<\/b><\/p>\n<pre><code class=\"javascript\">&lt;style&gt;\n  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }\n&lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;!-- \u0417\u0434\u0435\u0441\u044c \u0432 \u044d\u0442\u043e\u043c &quot;\u043e\u043a\u043e\u0448\u0435\u0447\u043a\u0435&quot; \u043a\u043b\u0438\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u0438\u0434\u0435\u0442\u044c \u0441\u0435\u0431\u044f --&gt;\n&lt;video autoplay id=&quot;videoObjectHtml5ApiServer&quot;&gt;&lt;\/video&gt;\n\n&lt;script type=&quot;application\/javascript&quot;&gt;\n  var\n        video = document.getElementById(&#039;videoObjectHtml5ApiServer&#039;);\n\n\/\/ \u0435\u0441\u043b\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d MediaDevices API, \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u0430\u043c\u0435\u0440\u0435 (\u043c\u043e\u0436\u043d\u043e \u0435\u0449\u0435 \u0438 \u043a \u043c\u0438\u043a\u0440\u043e\u0444\u043e\u043d\u0443)\n\/\/ getUserMedia \u0432\u0435\u0440\u043d\u0435\u0442 \u043e\u0431\u0435\u0449\u0430\u043d\u0438\u0435, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a \u0432 \u043a\u043e\u043b\u0431\u0435\u043a\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432 video \u043e\u0431\u044a\u0435\u043a\u0442 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435\n\nif (navigator.mediaDevices.getUserMedia) {\n        navigator.mediaDevices.getUserMedia({video: true}).then(function (stream) {\n          \/\/ \u0432\u0438\u0434\u0435\u043e \u043f\u043e\u0442\u043e\u043a \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u043c \u043a video \u0442\u0435\u0433\u0443, \u0447\u0442\u043e\u0431\u044b \u043a\u043b\u0438\u0435\u043d\u0442 \u043c\u043e\u0433 \u0432\u0438\u0434\u0435\u0442\u044c \u0441\u0435\u0431\u044f \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \n          video.srcObject = s;\n          var\n            recorderOptions = {\n                mimeType: &#039;video\/webm; codecs=vp8&#039; \/\/ \u0431\u0443\u0434\u0435\u043c \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a \u0432 \u0444\u043e\u0440\u043c\u0430\u0442 webm \u043a\u043e\u0434\u0435\u043a\u043e\u043c vp8\n              },\n              mediaRecorder = new MediaRecorder(s, recorderOptions ), \/\/ \u043e\u0431\u044a\u0435\u043a\u0442 MediaRecorder\n              socket = new WebSocket(&#039;ws:\/\/127.0.0.1:3000\/ws&#039;);\n\n               mediaRecorder.ondataavailable = function(e) {\n                if (e.data &amp;&amp; e.data.size &gt; 0) {\n                  \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u0443\u0441\u043e\u0447\u0435\u043a \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a\u0430 \u0432 e.data\n                 socket.send(e.data);\n                }\n            }\n\n            mediaRecorder.start(100); \/\/ \u0434\u0435\u043b\u0438\u0442 \u043f\u043e\u0442\u043e\u043a \u043d\u0430 \u043a\u0443\u0441\u043e\u0447\u043a\u0438 \u043f\u043e 100 \u043c\u0441 \u043a\u0430\u0436\u0434\u044b\u0439\n\n        }).catch(function (err) { console.log(err); });\n}\n&lt;\/script&gt;\n<\/code><\/pre>\n<p>\u0422\u0440\u0430\u043d\u0441\u043b\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u0430 \u0433\u043e\u0442\u043e\u0432\u0430! \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435. \u0427\u0442\u043e \u043d\u0430\u043c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f? \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445 \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435 \u0441\u043e\u043a\u0435\u0442-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435. \u041d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442 WebSocket \u0432\u0435\u0448\u0430\u0435\u043c \u00ab\u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044c\u00bb (listener), \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 &#8216;message&#8217;. \u041f\u043e\u043b\u0443\u0447\u0438\u0432 \u043a\u0443\u0441\u043e\u0447\u0435\u043a \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u0440\u043e\u0434\u043a\u0430\u0441\u0442\u0438\u0442 \u0435\u0433\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430\u043c, \u0442\u043e \u0435\u0441\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c. \u041d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 callback-\u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u0430\u044f \u0441 \u00ab\u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u0435\u043c\u00bb \u0441\u043e\u0431\u044b\u0442\u0438\u044f &#8216;message&#8217;, \u0432 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441\u0430\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u2014 \u043a\u0443\u0441\u043e\u0447\u0435\u043a \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a\u0430, \u0437\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 vp8. <\/p>\n<p>                        <b class=\"spoiler_title\">Video-Stream empfangen<\/b><\/p>\n<pre><code class=\"javascript\">&lt;style&gt;\n  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }\n&lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;!-- \u0417\u0434\u0435\u0441\u044c \u0432 \u044d\u0442\u043e\u043c &quot;\u043e\u043a\u043e\u0448\u0435\u0447\u043a\u0435&quot; \u043a\u043b\u0438\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u0438\u0434\u0435\u0442\u044c \u0442\u0435\u0431\u044f --&gt;\n&lt;video autoplay id=&quot;videoObjectHtml5ApiServer&quot;&gt;&lt;\/video&gt;\n\n&lt;script type=&quot;application\/javascript&quot;&gt;\n  var\n        video = document.getElementById(&#039;videoObjectHtml5ApiServer&#039;),\n         socket = new WebSocket(&#039;ws:\/\/127.0.0.1:3000\/ws&#039;), \n         arrayOfBlobs = [];\n\n         socket.addEventListener(&#039;message&#039;, function (event) {\n                \/\/ &quot;\u043a\u043b\u0430\u0434\u0435\u043c&quot; \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043a\u0443\u0441\u043e\u0447\u0435\u043a \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 \n                arrayOfBlobs.push(event.data);\n                \/\/ \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u043c \u0447\u0438\u0442\u0430\u0442\u044c \u043a\u0443\u0441\u043e\u0447\u043a\u0438\n                readChunk();\n            });\n&lt;\/script&gt;\n<\/code><\/pre>\n<p>Lange Zeit habe ich versucht zu verstehen, warum man die empfangenen St\u00fccke nicht sofort an das video-Element zur Wiedergabe senden kann, aber es stellte sich heraus, dass man das nicht so machen kann. Zuerst muss das St\u00fcck in einen speziellen Puffer gelegt werden, der mit dem video-Element verbunden ist, und erst dann wird der Video-Stream wiedergegeben. Daf\u00fcr ben\u00f6tigen wir <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/MediaSource\">MediaSource API<\/a><\/noindex> und <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/FileReader\">FileReader API<\/a><\/noindex>.<\/p>\n<p>MediaSource fungiert als Vermittler zwischen dem Wiedergabeobjekt und der Quelle des Medienstreams. Das MediaSource-Objekt enth\u00e4lt einen Puffer, der mit der Video-\/Audioquelle verbunden ist. Eine Besonderheit ist, dass der Puffer nur Daten vom Typ Uint8 enthalten kann, weshalb zur Erstellung eines solchen Puffers ein FileReader erforderlich ist. Schauen Sie sich den Code an, dann wird es klarer:<\/p>\n<p>                        <b class=\"spoiler_title\">Videostream wird wiedergegeben<\/b><\/p>\n<pre><code class=\"javascript\">&lt;style&gt;\n  #videoObjectHtml5ApiServer { width: 320px; height: 240px; background: #666; }\n&lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n&lt;!-- \u0417\u0434\u0435\u0441\u044c \u0432 \u044d\u0442\u043e\u043c &quot;\u043e\u043a\u043e\u0448\u0435\u0447\u043a\u0435&quot; \u043a\u043b\u0438\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u0438\u0434\u0435\u0442\u044c \u0442\u0435\u0431\u044f --&gt;\n&lt;video autoplay id=&quot;videoObjectHtml5ApiServer&quot;&gt;&lt;\/video&gt;\n\n&lt;script type=&quot;application\/javascript&quot;&gt;\n  var\n        video = document.getElementById(&#039;videoObjectHtml5ApiServer&#039;),\n         socket = new WebSocket(&#039;ws:\/\/127.0.0.1:3000\/ws&#039;),\n        mediaSource = new MediaSource(), \/\/ \u043e\u0431\u044a\u0435\u043a\u0442 MediaSource\n        vid2url = URL.createObjectURL(mediaSource), \/\/ \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 URL \u0434\u043b\u044f \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u043d\u0438\u044f \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a\u0430 \u0441 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u0435\u043b\u0435\u043c\n        arrayOfBlobs = [],\n        sourceBuffer = null; \/\/ \u0431\u0443\u0444\u0435\u0440, \u043f\u043e\u043a\u0430 \u043d\u0443\u043b\u044c-\u043e\u0431\u044a\u0435\u043a\u0442\n\n         socket.addEventListener(&#039;message&#039;, function (event) {\n                \/\/ &quot;\u043a\u043b\u0430\u0434\u0435\u043c&quot; \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043a\u0443\u0441\u043e\u0447\u0435\u043a \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 \n                arrayOfBlobs.push(event.data);\n                \/\/ \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u043c \u0447\u0438\u0442\u0430\u0442\u044c \u043a\u0443\u0441\u043e\u0447\u043a\u0438\n                readChunk();\n            });\n\n         \/\/ \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e MediaSource \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d , \u0447\u0442\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0433\u043e\u0442\u043e\u0432 \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u043a\u0443\u0441\u043e\u0447\u043a\u0438 \n        \/\/ \u0432\u0438\u0434\u0435\u043e\/\u0430\u0443\u0434\u0438\u043e \u043f\u043e\u0442\u043e\u043a\u0430\n        \/\/ \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0431\u0443\u0444\u0435\u0440 , \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0431\u0443\u0444\u0435\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u043d\u0430\u0442\u044c \u0432 \u043a\u0430\u043a\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \n        \/\/ \u043a\u0430\u043a\u0438\u043c \u043a\u043e\u0434\u0435\u043a\u043e\u043c \u0431\u044b\u043b \u0437\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d \u043f\u043e\u0442\u043e\u043a, \u0447\u0442\u043e\u0431\u044b \u0442\u0435\u043c \u0436\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a\n         mediaSource.addEventListener(&#039;sourceopen&#039;, function() {\n            var mediaSource = this;\n            sourceBuffer = mediaSource.addSourceBuffer(&quot;video\/webm; codecs=&quot;vp8&quot;&quot;);\n        });\n\n      function readChunk() {\n        var reader = new FileReader();\n        reader.onload = function(e) { \n          \/\/ \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e FileReader \u0431\u0443\u0434\u0435\u0442 \u0433\u043e\u0442\u043e\u0432, \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442 \u0441\u0435\u0431\u0435 \u043a\u0443\u0441\u043e\u0447\u0435\u043a \u0432\u0438\u0434\u0435\u043e\u043f\u043e\u0442\u043e\u043a\u0430\n          \/\/ \u043c\u044b &quot;\u043f\u0440\u0438\u0446\u0435\u043f\u043b\u044f\u0435\u043c&quot; \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432 Uint8Array (\u0431\u044b\u043b Blob) \u043a\u0443\u0441\u043e\u0447\u0435\u043a \u0432 \u0431\u0443\u0444\u0435\u0440, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0439\n          \/\/ \u0441 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u0435\u043b\u0435\u043c, \u0438 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043a\u0443\u0441\u043e\u0447\u0435\u043a \u0432\u0438\u0434\u0435\u043e\/\u0430\u0443\u0434\u0438\u043e\n          sourceBuffer.appendBuffer(new Uint8Array(e.target.result));\n\n          reader.onload = null;\n        }\n        reader.readAsArrayBuffer(arrayOfBlobs.shift());\n      }\n&lt;\/script&gt;\n<\/code><\/pre>\n<p>Der Prototyp des Streaming-Dienstes ist fertig. Der Hauptnachteil besteht darin, dass die Videoausgabe gegen\u00fcber der sendenden Seite um 100 ms verz\u00f6gert ist, was wir selbst festgelegt haben, als wir den Videostream vor der \u00dcbertragung an den Server aufgeteilt haben. Dar\u00fcber hinaus habe ich bemerkt, dass sich auf meinem Laptop im Laufe der Zeit ein Lag zwischen sendender und empfangender Seite aufgebaut hat, was deutlich zu sehen war. Ich begann, nach M\u00f6glichkeiten zu suchen, um dieses Problem zu beheben, und... stie\u00df auf <noindex><a rel=\"nofollow\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/RTCPeerConnection\">RTCPeerConnection API<\/a><\/noindex>, das eine nahtlose \u00dcbertragung von Videostreams erm\u00f6glicht, ohne die stream in kleinere Teile aufzuteilen. Der angesammelte Lag entsteht, weil im Browser vor der \u00dcbertragung jeder Teil in das Format webm umkodiert wird. Ich wollte nicht tiefer eingreifen, also begann ich, mich mit WebRTC zu besch\u00e4ftigen. Ich werde \u00fcber die Ergebnisse meiner Recherchen einen separaten Artikel schreiben, wenn ich denke, dass es f\u00fcr die Community interessant ist.<br \/>\n<br \/>Quelle: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/461769\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441\u0432\u043e\u0438\u043c\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0430\u043c\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0442\u0440\u0438\u043c\u043c\u0438\u043d\u0433 \u0432\u0438\u0434\u0435\u043e \u0447\u0435\u0440\u0435\u0437 websockets \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0442\u0438\u043f\u0430 Adobe Flash Player. \u0427\u0442\u043e \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0434\u0430\u043b\u0435\u0435. Adobe Flash \u2014 \u0440\u0430\u043d\u0435\u0435 Macromedia Flash, \u044d\u0442\u043e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0445 \u0432 \u0432\u0435\u0431-\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u0414\u043e \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f Media Stream API \u044d\u0442\u043e \u0431\u044b\u043b\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f \u0441\u0442\u0440\u0438\u043c\u043c\u0438\u043d\u0433\u0430 \u0441 \u0432\u0435\u0431-\u043a\u0430\u043c\u0435\u0440\u044b [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-94138","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441\u0432\u043e\u0438\u043c\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0430\u043c\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0442\u0440\u0438\u043c\u043c\u0438\u043d\u0433 \u0432\u0438\u0434\u0435\u043e \u0447\u0435\u0440\u0435\u0437 websockets \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0442\u0438\u043f\u0430 Adobe Flash Player. \u0427\u0442\u043e \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0434\u0430\u043b\u0435\u0435. Adobe Flash \u2014 \u0440\u0430\u043d\u0435\u0435 Macromedia Flash, \u044d\u0442\u043e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0445 \u0432 \u0432\u0435\u0431-\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u0414\u043e \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f Media Stream API \u044d\u0442\u043e \u0431\u044b\u043b\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f \u0441\u0442\u0440\u0438\u043c\u043c\u0438\u043d\u0433\u0430 \u0441 \u0432\u0435\u0431-\u043a\u0430\u043c\u0435\u0440\u044b\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/pochti-bespoleznyj-striming-vebkamery-iz-brauzera-media-stream-i-websockets\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47(\u041f\u043e\u0447\u0442\u0438) \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433 \u0432\u0435\u0431\u043a\u0430\u043c\u0435\u0440\u044b \u0438\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. Media Stream \u0438 Websockets | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441\u0432\u043e\u0438\u043c\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0430\u043c\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0442\u0440\u0438\u043c\u043c\u0438\u043d\u0433 \u0432\u0438\u0434\u0435\u043e \u0447\u0435\u0440\u0435\u0437 websockets \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0442\u0438\u043f\u0430 Adobe Flash Player. \u0427\u0442\u043e \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0434\u0430\u043b\u0435\u0435. Adobe Flash \u2014 \u0440\u0430\u043d\u0435\u0435 Macromedia Flash, \u044d\u0442\u043e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0445 \u0432 \u0432\u0435\u0431-\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u0414\u043e \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f Media Stream API \u044d\u0442\u043e \u0431\u044b\u043b\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f \u0441\u0442\u0440\u0438\u043c\u043c\u0438\u043d\u0433\u0430 \u0441 \u0432\u0435\u0431-\u043a\u0430\u043c\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/pochti-bespoleznyj-striming-vebkamery-iz-brauzera-media-stream-i-websockets\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-09-13T05:42:42+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-09-13T05:42:42+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47(Fast) nutzloses Streaming von Webcams aus dem Browser. Media Stream und Websockets | ProHoster","description":"In diesem Artikel m\u00f6chte ich meine Versuche teilen, Video \u00fcber Websockets zu streamen, ohne dabei auf externe Browser-Plugins wie Adobe Flash Player zur\u00fcckzugreifen. Was daraus entstanden ist, lesen Sie weiter. Adobe Flash \u2013 fr\u00fcher Macromedia Flash, ist eine Plattform zur Erstellung von Anwendungen, die im Webbrowser funktionieren. Vor der Einf\u00fchrung der Media Stream API war dies praktisch die einzige Plattform f\u00fcr das Streaming von Webcam-Inhalten.","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/pochti-bespoleznyj-striming-vebkamery-iz-brauzera-media-stream-i-websockets","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47(\u041f\u043e\u0447\u0442\u0438) \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u0441\u0442\u0440\u0438\u043c\u0438\u043d\u0433 \u0432\u0435\u0431\u043a\u0430\u043c\u0435\u0440\u044b \u0438\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. Media Stream \u0438 Websockets | ProHoster","og:description":"\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441\u0432\u043e\u0438\u043c\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0430\u043c\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0442\u0440\u0438\u043c\u043c\u0438\u043d\u0433 \u0432\u0438\u0434\u0435\u043e \u0447\u0435\u0440\u0435\u0437 websockets \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0442\u0438\u043f\u0430 Adobe Flash Player. \u0427\u0442\u043e \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0434\u0430\u043b\u0435\u0435. Adobe Flash \u2014 \u0440\u0430\u043d\u0435\u0435 Macromedia Flash, \u044d\u0442\u043e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0445 \u0432 \u0432\u0435\u0431-\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u0414\u043e \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f Media Stream API \u044d\u0442\u043e \u0431\u044b\u043b\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f \u0441\u0442\u0440\u0438\u043c\u043c\u0438\u043d\u0433\u0430 \u0441 \u0432\u0435\u0431-\u043a\u0430\u043c\u0435\u0440\u044b","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/pochti-bespoleznyj-striming-vebkamery-iz-brauzera-media-stream-i-websockets","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-09-13T05:42:42+00:00","article:modified_time":"2020-09-13T05:42:42+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"94138","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 11:32:23","updated":"2022-10-01 11:18:30"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/94138","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=94138"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/94138\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=94138"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=94138"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=94138"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}