यस लेखमा म तेस्रो-पक्ष ब्राउजर प्लगइनहरू जस्तै Adobe Flash Player प्रयोग नगरी वेबसकेटहरू मार्फत भिडियो स्ट्रिम गर्ने मेरो प्रयासहरू साझा गर्न चाहन्छु। यो के आयो पत्ता लगाउन पढ्नुहोस्।
Adobe Flash, पहिले Macromedia Flash, वेब ब्राउजरमा चल्ने एपहरू सिर्जना गर्ने प्लेटफर्म हो। मिडिया स्ट्रिम API को परिचय अघि, यो व्यावहारिक रूपमा वेबक्यामबाट भिडियो र आवाज स्ट्रिमिङको लागि एकमात्र प्लेटफर्म थियो, साथै ब्राउजरमा विभिन्न प्रकारका सम्मेलनहरू र च्याटहरू सिर्जना गर्न। मिडिया जानकारी RTMP (रियल टाइम मेसेजिङ प्रोटोकल) लाई प्रसारण गर्ने प्रोटोकल वास्तवमा लामो समयको लागि बन्द थियो, जसको अर्थ: यदि तपाइँ आफ्नो स्ट्रिमिङ सेवालाई बढावा दिन चाहनुहुन्छ भने, Adobe आफैंबाट सफ्टवेयर प्रयोग गर्न पर्याप्त दयालु हुनुहोस् - Adobe Media Server (AMS)।
2012 मा केहि समय पछि, Adobe "छाड्यो र यसलाई थुक्यो" जनतामा।
Adobe Flash प्लेटफर्म २० वर्ष भन्दा पुरानो हो, जुन समयमा धेरै महत्वपूर्ण कमजोरीहरू पत्ता लगाइएको छ, समर्थन
मेरो परियोजनाको लागि, मैले तुरुन्तै ब्राउजरमा फ्ल्यासको प्रयोगलाई पूर्ण रूपमा त्याग्न निर्णय गरें। मैले माथिको मुख्य कारण संकेत गरें; फ्ल्यास पनि मोबाइल प्लेटफर्महरूमा समर्थित छैन, र म वास्तवमै Windows (वाइन इमुलेटर) मा विकासको लागि Adobe Flash प्रयोग गर्न चाहन्न। त्यसैले मैले जाभास्क्रिप्टमा क्लाइन्ट लेख्न सेट गरें। यो केवल एक प्रोटोटाइप हुनेछ, किनकि पछि मैले स्ट्रिमिङ p2p मा आधारित धेरै कुशलतापूर्वक गर्न सकिन्छ भनेर सिकें, केवल मेरो लागि यो साथी - सर्भर - साथीहरू हुनेछ, तर त्यो अर्को पटक, किनभने यो अझै तयार छैन।
सुरु गर्न, हामीलाई वास्तविक वेबसकेट सर्भर चाहिन्छ। मैले मेलोडी गो प्याकेजमा आधारित सरल बनाएको छु:
सर्भर कोड
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)
}
ग्राहक (स्ट्रिमिङ साइड) मा, तपाईंले पहिले क्यामेरा पहुँच गर्न आवश्यक छ। यो मार्फत गरिन्छ
हामी क्यामेरा/माइक्रोफोन मार्फत पहुँच (अनुमति) प्राप्त गर्छौं
अर्को, getUserMedia() ले एउटा वाचा फर्काउँछ, जसमा यसले मिडियास्ट्रिम वस्तु पास गर्छ - भिडियो-अडियो डेटाको स्ट्रिम। हामी यो वस्तुलाई भिडियो तत्वको src गुणमा नियुक्त गर्छौं। कोड:
प्रसारण पक्ष
<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>
सकेटहरूमा भिडियो स्ट्रिम प्रसारण गर्न, तपाईंले यसलाई कतै इन्कोड गर्न आवश्यक छ, यसलाई बफर गर्नुहोस्, र यसलाई भागहरूमा पठाउनुहोस्। कच्चा भिडियो स्ट्रिम वेबसकेट मार्फत प्रसारण गर्न सकिँदैन। यो हाम्रो सहयोगको लागि आउँदछ
हामी भिडियो स्ट्रिम इन्कोड गर्छौं, यसलाई टुक्राहरूमा तोड्छौं
<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>
अब वेबसकेट मार्फत प्रसारण थपौं। अचम्मको कुरा, तपाईलाई यसको लागि चाहिने सबै वस्तु हो
हामी सर्भरमा भिडियो स्ट्रिम प्रसारण गर्छौं
<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>
प्रसारण पक्ष तयार छ! अब एक भिडियो स्ट्रिम प्राप्त गर्न र ग्राहक मा प्रदर्शन गर्न प्रयास गरौं। हामीलाई यसको लागि के चाहिन्छ? पहिले, निस्सन्देह, सकेट जडान। हामी WebSocket वस्तुमा "श्रोता" संलग्न गर्छौं र 'सन्देश' घटनाको सदस्यता लिन्छौं। बाइनरी डाटाको एक टुक्रा प्राप्त गरिसकेपछि, हाम्रो सर्भरले यसलाई ग्राहकहरूलाई प्रसारण गर्दछ, त्यो हो, ग्राहकहरू। यस अवस्थामा, 'सन्देश' घटनाको "श्रोता" सँग सम्बन्धित कलब्याक प्रकार्य ग्राहकमा ट्रिगर हुन्छ; वस्तु आफैं प्रकार्य तर्कमा पास हुन्छ - vp8 द्वारा इन्कोड गरिएको भिडियो स्ट्रिमको टुक्रा।
हामी भिडियो स्ट्रिम स्वीकार गर्छौं
<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>
लामो समयको लागि मैले बुझ्ने प्रयास गरें किन तुरुन्तै प्राप्त गरिएका टुक्राहरूलाई प्लेब्याकको लागि भिडियो तत्वमा पठाउन असम्भव छ, तर यो पत्ता लाग्यो कि यो गर्न सकिँदैन, निस्सन्देह, तपाईंले पहिले टुक्रालाई विशेष बफरमा राख्नुपर्छ। भिडियो तत्व, र त्यसपछि मात्र यो भिडियो स्ट्रिम प्ले सुरु हुनेछ। यसका लागि तपाईलाई आवश्यक पर्नेछ
MediaSource मिडिया प्लेब्याक वस्तु र यो मिडिया स्ट्रिम को स्रोत बीच मध्यस्थता को रूप मा काम गर्दछ। MediaSource वस्तुले भिडियो/अडियो स्ट्रिमको स्रोतको लागि प्लग गर्न मिल्ने बफर समावेश गर्दछ। एउटा विशेषता यो हो कि बफरले Uint8 डाटा मात्र समात्न सक्छ, त्यसैले तपाइँलाई यस्तो बफर सिर्जना गर्न FileReader चाहिन्छ। कोड हेर्नुहोस् र यो थप स्पष्ट हुनेछ:
भिडियो स्ट्रिम प्ले गर्दै
<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>
स्ट्रिमिङ सेवाको प्रोटोटाइप तयार छ। मुख्य हानि यो हो कि भिडियो प्लेब्याक 100 ms द्वारा प्रसारण पक्ष पछि पछि हुनेछ; सर्भरमा प्रसारण गर्नु अघि भिडियो स्ट्रिम विभाजन गर्दा हामीले यसलाई आफैं सेट गर्छौं। यसबाहेक, जब मैले मेरो ल्यापटपमा जाँच गरें, प्रसारण र प्राप्त गर्ने पक्षहरू बीचको ढिलाइ बिस्तारै जम्मा भयो, यो स्पष्ट रूपमा देखिन्थ्यो। मैले यो बेफाइदालाई पार गर्ने तरिकाहरू खोज्न थालें, र... भेटें
स्रोत: www.habr.com