亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

監(jiān)聽開始事件

  • EventTarget.addEventListener() 方法將指定的監(jiān)聽器注冊(cè)到 EventTarget 上,當(dāng)該對(duì)象觸發(fā)指定的事件時(shí),指定的回調(diào)函數(shù)就會(huì)被執(zhí)行。 事件目標(biāo)可以是一個(gè)文檔上的元素 Element,Document和Window或者任何其他支持事件的對(duì)象 (比如 XMLHttpRequest)。
  • addEventListener()的工作原理是將實(shí)現(xiàn)EventListener的函數(shù)或?qū)ο筇砑拥秸{(diào)用它的EventTarget上的指定事件類型的事件偵聽器列表中。
document.querySelector('button#start').addEventListener('click', async () => {
    document.querySelector('button#start').disabled = true;
    const constraints = {
        audio: {},
        video: {
            width: 1280, height: 720
        }
    };
    await init(constraints);
});

獲取音視頻軌道

  • MediaDevices.getUserMedia() 會(huì)提示用戶給予使用媒體輸入的許可,媒體輸入會(huì)產(chǎn)生一個(gè)MediaStream,里面包含了請(qǐng)求的媒體類型的軌道。此流可以包含一個(gè)視頻軌道(來自硬件或者虛擬視頻源,比如相機(jī)、視頻采集設(shè)備和屏幕共享服務(wù)等等)、一個(gè)音頻軌道(同樣來自硬件或虛擬音頻源,比如麥克風(fēng)、A/D轉(zhuǎn)換器等等),也可能是其它軌道類型。
  • 它返回一個(gè) Promise 對(duì)象,成功后會(huì)resolve回調(diào)一個(gè) MediaStream 對(duì)象。若用戶拒絕了使用權(quán)限,或者需要的媒體源不可用,promise會(huì)reject回調(diào)一個(gè) PermissionDeniedError 或者 NotFoundError 。
async function init(constraints) {
    try {
        const stream = await navigator.mediaDevices.getUserMedia(constraints);
        handleSuccess(stream);
    } catch (e) {
        console.error('navigator.getUserMedia error:', e);
    }
}
  • htmlMediaElement 接口的 srcObject 屬性設(shè)定或返回一個(gè)對(duì)象,這個(gè)對(duì)象提供了一個(gè)與HTMLMediaElement關(guān)聯(lián)的媒體源,這個(gè)對(duì)象通常是 MediaStream ,但根據(jù)規(guī)范可以是 MediaSource, Blob 或者 File。
function handleSuccess(stream) {
    recordButton.disabled = false;
    window.stream = stream;
    const gumVideo = document.querySelector('video#gum');
    gumVideo.srcObject = stream;
}

錄制媒體流

  • MediaRecorder() 構(gòu)造函數(shù)會(huì)創(chuàng)建一個(gè)對(duì)指定的 MediaStream 進(jìn)行錄制的 MediaRecorder 對(duì)象
  • MediaRecorder.ondataavailable 事件處理程序API處理dataavailable事件,在響應(yīng)運(yùn)行代碼Blob數(shù)據(jù)被提供使用。
  • dataavailable當(dāng)MediaRecorder將媒體數(shù)據(jù)傳遞到您的應(yīng)用程序以供使用時(shí),將觸發(fā)該事件。數(shù)據(jù)在包含數(shù)據(jù)的Blob對(duì)象中提供。這在四種情況下發(fā)生:
    • 媒體流結(jié)束時(shí),所有尚未傳遞到ondataavailable處理程序的媒體數(shù)據(jù)都將在單個(gè)Blob中傳遞。
    • 當(dāng)調(diào)用MediaRecorder.stop() (en-US)時(shí),自記錄開始或dataavailable事件最后一次發(fā)生以來已捕 獲的所有媒體數(shù)據(jù)都將傳遞到Blob中;此后,捕獲結(jié)束。
    • 調(diào)用MediaRecorder.requestData() (en-US) dataavailable時(shí),將傳遞自記錄開始或事件最后一次發(fā)生以來捕獲的所有媒體數(shù)據(jù);然后Blob創(chuàng)建一個(gè)新文件,并將媒體捕獲繼續(xù)到該blob中。
    • 如果將timeslice屬性傳遞到開始媒體捕獲的MediaRecorder.start() (en-US)方法中,dataavailable則每timeslice毫秒觸發(fā)一次事件。這意味著每個(gè)Blob都有特定的持續(xù)時(shí)間(最后一個(gè)Blob除外,后者可能更短,因?yàn)樗鼘⑹亲陨洗问录詠硎O碌乃袞|西)。
let mediaRecorder;
const recordButton = document.querySelector('button#record');

recordButton.addEventListener('click', () => {
    if (recordButton.textContent === '開始記錄') {
        startRecording();
    } else {
        stopRecording();
        recordButton.textContent = '開始記錄';
        playButton.disabled = false;
    }
});

function startRecording() {
    recordedBlobs = [];
    try {
        mediaRecorder = new MediaRecorder(window.stream);
    } catch (e) {
        console.error('創(chuàng)建MediaRecorder時(shí)異常:', e);
    }
    recordButton.textContent = '停止記錄';
    playButton.disabled = true;
    mediaRecorder.ondataavailable = handleDataAvailable;
    mediaRecorder.start();
}

function stopRecording() {
    mediaRecorder.stop();
}

function handleDataAvailable(event) {
    if (event.data && event.data.size > 0) {
        recordedBlobs.push(event.data);
    }
}

播放媒體流

  • URL.createObjectURL() 靜態(tài)方法會(huì)創(chuàng)建一個(gè) DOMString,其中包含一個(gè)表示參數(shù)中給出的對(duì)象的URL。這個(gè) URL 的生命周期和創(chuàng)建它的窗口中的 document 綁定。這個(gè)新的URL 對(duì)象表示指定的 File 對(duì)象或 Blob 對(duì)象。
let recordedBlobs;
const recordedVideo = document.querySelector('video#recorded');
const playButton = document.querySelector('button#play');

playButton.addEventListener('click', () => {
    const superBuffer = new Blob(recordedBlobs, { type: 'video/webm' });
    recordedVideo.src = null;
    recordedVideo.srcObject = null;
    recordedVideo.src = window.URL.createObjectURL(superBuffer);
    recordedVideo.controls = true;
    recordedVideo.play();
});

HTML

<link rel="stylesheet" href="./index.css">

<video id="gum" autoplay></video>
<video id="recorded"></video>
<div>
    <button id="start">開始</button>
    <button id="record" disabled>開始記錄</button>
    <button id="play" disabled>Play</button>
</div>

<script src="./index.js"></script>

CSS

button {
    margin: 0 3px 10px 0;
    padding-left: 2px;
    padding-right: 2px;
    width: 99px;
}
  
button:last-of-type {
    margin: 0;
}
  
video {
    vertical-align: top;
    --width: 25vw;
    width: var(--width);
    height: calc(var(--width) * 0.5625);
}
  
video:last-of-type {
    margin: 0 0 20px 0;
}
  
video#gumVideo {
    margin: 0 20px 20px 0;
}

JAVAScript

let mediaRecorder;
let recordedBlobs;

const recordedVideo = document.querySelector('video#recorded');
const recordButton = document.querySelector('button#record');
recordButton.addEventListener('click', () => {
    if (recordButton.textContent === '開始記錄') {
        startRecording();
    } else {
        stopRecording();
        recordButton.textContent = '開始記錄';
        playButton.disabled = false;
    }
});

const playButton = document.querySelector('button#play');
playButton.addEventListener('click', () => {
    const superBuffer = new Blob(recordedBlobs, { type: 'video/webm' });
    recordedVideo.src = null;
    recordedVideo.srcObject = null;
    recordedVideo.src = window.URL.createObjectURL(superBuffer);
    recordedVideo.controls = true;
    recordedVideo.play();
});

function handleDataAvailable(event) {
    if (event.data && event.data.size > 0) {
        recordedBlobs.push(event.data);
    }
}

function startRecording() {
    recordedBlobs = [];
    try {
        mediaRecorder = new MediaRecorder(window.stream);
    } catch (e) {
        console.error('創(chuàng)建MediaRecorder時(shí)異常:', e);
    }
    recordButton.textContent = '停止記錄';
    playButton.disabled = true;
    mediaRecorder.ondataavailable = handleDataAvailable;
    mediaRecorder.start();
}

function stopRecording() {
    mediaRecorder.stop();
}

function handleSuccess(stream) {
    recordButton.disabled = false;
    window.stream = stream;
    const gumVideo = document.querySelector('video#gum');
    gumVideo.srcObject = stream;
}

async function init(constraints) {
    try {
        const stream = await navigator.mediaDevices.getUserMedia(constraints);
        handleSuccess(stream);
    } catch (e) {
        console.error('navigator.getUserMedia error:', e);
    }
}

document.querySelector('button#start').addEventListener('click', async () => {
    document.querySelector('button#start').disabled = true;
    const constraints = {
        audio: {},
        video: {
            width: 1280, height: 720
        }
    };
    await init(constraints);
});
web技術(shù)分享|WebRTC記錄音視頻流

 

分享到:
標(biāo)簽:視頻
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定