鸟语天空
WebRTC 录制视频流
post by:追风剑情 2024-1-8 14:50

录制媒体流

const mediaRecorder = new MediaRecorder(stream[, options]);  

参数: stream,MediaStrem 对象,录制源; options,类型为 MediaRecorderOptions 的可选参数

MediaRecorderOptions 属性说明
属性 说明
mimeType 指定录制流的编码格式
调用 MediaRecorder.isTypeSupported()方法检查当前浏览器是否支持指定的编码格式。如果当前浏览器不支持指定的编码格式,则该构造函数抛出异常 NotSupportedError
audioBitsPerSecond 指定录制流的音频码率
videoBitsPerSecond 指定录制流的视频码率
bitsPerSecond 指定录制流中音视频的码率,用于替代 audioBitsPerSecond 和 videoBitsPerSecond 属性,如果这两个属性只指定了一个,则 bitsPerSecond 将替代另外一个
audioBitrateMode 指定音频码率模式,取值为 cbr 或 vbr。cbr 指以固定码率进行编码,vbr 指以可变码率进行编码

如果没有指定录制流的码率,则默认视频码率为 2.5Mbps,音频码率取决于采样率和通道数。

如下面代码清单所示,创建录制流,指定的视频编码格式是 mp4,如果创建成功则返回 MediaRecorder 对象,创建失败则打印错误信息并返回 null。

function getRecorder(stream) {
	const options = {
		audioBitsPerSecond : 128000,
		videoBitsPerSecond : 2500000,
		mimeType : 'video/mp4'
	}
	
	let mediaRecorder = null;
	try {
		mediaRecorder = new MediaRecorder(stream,options);
	} catch(e) {
		console.error('Exception while creating MediaRecorder: ' + e);
	}
	return mediaRecorder;
}  

MediaRecorder 属性

1.mimeType 只读

返回构造 MediaRecorder 对象时指定的 MIME 编码格式,如果在构造时未指定,则返回浏览器默认使用的编码格式,类型为字符串。

下面代码清单调用 getUserMedia 方法获取音视频流,并指定 mp4 编码格式进行录制。

if (navigator.mediaDevices) {
	console.log('getUserMedia supported.');
	
	const constraints = { audio: true, video: true };
	const chunks = [];
	
	navigator.mediaDevices.getUserMedia(constraints)
		.then(stream => {
			const options = {
				audioBitsPerSecond: 128000,
				videoBitsPerSecond: 2500000,
				mimeType:'video/mp4'
			}
			const mediaRecorder = new MediaRecorder(stream,options);
			console.log(mediaRecorder.mimeType);
		}).catch(error => {
			console.log(error.message);
		});
}  

2.state 只读

返回 MediaRecorder 对象的当前状态,类型为 RecordingState。

RecordingState 属性说明
属性 说明
inactive 没有进行录制,原因可能是录制没有开始或者已经停止
recording 录制正在进行
paused 录制已开始,当前处于暂停状态

下面的代码清单在 onclick 事件的处理函数中启动录制并打印录制的状态

record.onclick = () => {
	mediaRecorder.start();
	console.log(mediaRecorder.state);
}

3.stream 只读

返回构造 MediaRecorder 对象时指定的媒体流对象,类型为 MediaStream。

4.videoBitsPerSecond 只读

返回当前的视频码率,可能与构造时指定的码率不同,类型为数值。

5.audioBitsPerSecond 只读

返回当前的音频码率,可能与构造时指定的码率不同,类型为数值。

5.audioBitrateMode 只读

返回音频轨道的码率模式,类型为 BitrateMode。

BitrateMode 的枚举值
枚举值 说明
cbr cbr指以固定码率进行编码。
vbr vbr指以可变码率进行编码。

MediaRecorder 方法

1.isTypeSupported() 静态方法

检查当前浏览器是否支持指定的 MIME 格式。

const canRecord = MediaRecorder.isTypeSupported(mimeType)

参数: mimeType,MIME 媒体格式。
返回值: 类型为 Boolean,如果支持该 mimeType 则返回 true,否则返回 false。

下面的代码清单检测 types 数组中的 mimeType,如果当前浏览器支持此 mimeType,则打印 YES,如果不支持则打印 NO。

const types = [	"video/webm",
			    "audio/webm",
				"video/webm\;codecs=vp8",
				"video/webm\;codecs=daala",
				"video/webm\;codecs=h264",
				"audio/webm\;codecs=opus",
				"video/mpeg"];
for (let i in types) {
	console.log("Is "+ types[i] + " supported? "+(MediaRecorder.isTypeSupported(types[i]) ? "YES” : "NO"));
}

2.requestData() 方法

该方法触发 dataavailable 事件,事件包含 Blob 格式的录制数据。该方法通常需要周期性调用。

mediaRecorder.requestData()

参数: 无。
返回值: 无。如果 MediaRecorder.state 不是 recording,将抛出异常 InvalidState。

如下代码清单所示,每秒调用一次 requestData() 方法,并在 dataavailable 事件处理函数中获取录制数据。

this.mediaRecorder.ondataavailable = (event) => {
	if (event.data.size > 0) {
		this.recordedChunks .push(event.data);
	}
};
this.recorderIntervalHandler = setInterval(() => {
	this.mediaRecorder.requestData();
}, 1000);

3.start(timeslice) 方法

启动录制,将录制数据写入 Blob 对象。

mediaRecorder.start(timeslice)

参数: timeslice,可选参数,用于设置录制缓存区时长,单位为毫秒(ms)。如果指定了 timeslice,当 Blob 缓存区写满后,触发 dataavailable 事件,并重新创建一个 Blob 对象。如果未指定 timeslice,则录制数据会始终写人同一个 Blob 对象,直到调用 requestData()方法才会重新创建新的 Blob 对象。
返回值:无。如果调用出错,会抛出异常。

start 异常说明
异常 说明
InvalidModificationError 录制源的媒体轨道发生了变化,录制时不能添加或删除媒体轨道
InvalidStateError MediaRecorder 当前状态不是 inactive
NotSupportedError 媒体源处于 inactive 状态,或者媒体轨道不可录制
SecurityError 媒体流不允许录制
UnknownError 其他未知错误

下面的代码清单启动录制,并将 Blob 缓存区设置为 100ms,缓存区满后触发 dataavailable 事件。

recorder.ondataavailable = (event) => {
	console.log(' Recorded chunk of size ' + event.data.size +"B");
	recordedChunks.push(event.data);
};

recorder.start(100);

4.MediaRecorder.pause() 方法

暂停录制。当调用该方法时,浏览器将产生如下行为。

5.MediaRecorder.resume() 方法

恢复录制。当调用该方法时,浏览器会产生如下行为。

下面的代码清单展示了暂停/恢复状态的切换。

pause.onclick = () =< {
	if(MediaRecorder.state === "recording") {
		//暂停录制。
		mediaRecorder.pause();
	} else if (MediaRecorder.state === "paused") {
		//恢复录制
		mediaRecorder.resume();
	}
}

MediaRecorder 事件

1.start 事件

当调用 MediaRecorder.start() 方法时触发该事件。此时启动录制,录制数据开始写人 Blob,对应事件句柄 onstart。

以下两种语法都可以为 start 事件设置处理函数。

MediaRecorder.onstart = (event) => { ... }
MediaRecorder.addEventListener('start', (event) => { ... })

下面的代码清单启动录制,并在 onstart 事件句柄中处理录制数据。

record.onclick = () => {
	mediaRecorder.start();
	console.log("recorder started");
}

mediaRecorder.onstart = () => {
	//start事件处理流程
}

2.pause 事件

当调用 MediaRecorder.pause() 方法时触发该事件。此时暂停录制数据,对应事件句柄 onpause。

以下两种语法都可以为 pause 事件设置处理函数。

MediaRecorder.onpause = (event) => { ... }
MediaRecorder.addEventListener('pause', (event) => { ... })

下面的代码清单在 onclick 事件中切换录制状态并在相应的事件句柄中输出日志。

pause.onclick = () => {
	if (mediaRecorder.state === "recording") {
		mediaRecorder.pause();
	} else if (mediaRecorder.state === "paused") {
		mediaRecorder.resume();
	}
}

mediaRecorder.onpause = () => {
	console.log("mediaRecorder paused!");
}

mediaRecorder.onresume = () => {
	console.log("mediaRecorder resumed!");
}

3.resume 事件

当调用 MediaRecorderresume() 方法时触发该事件。此时由暂停恢复录制,对应事件句柄 onresume。

以下两种语法都可以为 resume 事件设置处理函数。

MediaRecorder.onresume = (event) => { ... }
MediaRecorder.addEventListener('resume', (event) => { ... })

4.stop 事件

当调用 MediaRecorder.stop() 方法或媒体流中止时触发该事件。此时停止录制数据,对 应事件句柄 onstop。

以下两种语法都可以为 stop 事件设置处理函数。

MediaRecorder.onstop = (event) => { ... }
MediaRecorder.addEventListener('stop', (event) => { ... })

下面的代码清单在 ondataavailable 事件句柄中将录制的数据保存到 chunks 数组,当录制 停止时,使用 chunks 生成音频地址,回放录制的数据。

mediaRecorder.onstop = (e) => {
	console.log("data available after MediaRecorder.stop() called.");
	let audio = document.createElement ('audio');
	audio.controls = true;
	const blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' ));
	const audioURL = window.URL.createObjectURL(blob);
	audio.srcobject = audioURL;
	console.log("recorder stopped");
}

mediaRecorder.ondataavailable = (e) => {
	chunks.push(e.data);
}

5.dataavailable 事件

该事件用于处理录制数据,对应事件句柄 ondataavailable,以下情况会触发该事件。

以下两种语法都可以为 dataavailable 事件设置处理函数。

MediaRecorder.ondataavailable = (event) => { ... }
MediaRecorder.addEventListener('dataavailable', (event) => { ... })

6.error 事件

在创建录制对象或录制过程中出现错误时触发该事件,事件类型为 MediaRecorderErrorEvent,对应事件句柄 onerror。

以下两种语法都可以为 error 事件设置处理函数。

MediaRecorder.onerror = (event) => { ... }
MediaRecorder.addEventListener('error', (event) => { ... })

下表列出了该事件触发时的错误名,错误名可以通过 MediaRecorderErrorEvent.error.name 获取。

MediaRecorder 错误名
错误名 说明
InvalidStateError 在活跃状态调用了 start() 方法、resume() 方法以及在不活跃状态调用了 stop() 方法和 pause() 方法都会导致该错误
SecurityError 因为安全问题,该媒体流不允许被录制。比如使用 getUserMedia() 获取媒体流时,用户未通过授权
NotSupportedError 不支持传人 MIME 格式
UnknownError 其他未知错误

下面的代码清单实现了录制流函数 recordStream,在该函数中启动录制,保存录制数据并在出错时打印错误信息。

function recordstream(stream) {
	let bufferList = [];
	let recorder = new MediaRecorder(stream);
	recorder.ondataavailable = (event) => {
		bufferList.push(event.data);
	};
	
	recorder.onerror = (event) => {
		let error = event .error;
		switch (error.name) {
			case InvalidstateError:
				console.log("You can't record the video right now. Try again later.");
				break;
			case SecurityError:
				console.log("Recording the specified source is not allowed due to securityrestrictions.");
				break;
			default:
				console.log("A problem occurred while trying to record the video.");
				break;
		}
	};
	recorder.start(100);
	return recorder;
}

评论:
发表评论:
昵称

邮件地址 (选填)

个人主页 (选填)

内容