无法使用 webrtc MediaDevices 在反应应用程序中切换摄像头(从前到后)
Posted
技术标签:
【中文标题】无法使用 webrtc MediaDevices 在反应应用程序中切换摄像头(从前到后)【英文标题】:unable to switch camera (front to rear) in react application using webrtc MediaDevices 【发布时间】:2019-07-26 19:04:36 【问题描述】:这是我打算做的示例演示。 如果有人对此修复有任何想法以使其工作或任何新逻辑,请分享。
这个演示是通过使用 mediaStream API 和 使用 react-webcam 库,它实际上提供了在名为 videoConstraints=faceMode: 'user' or 'environment' 的道具的帮助下管理相机视图的选项,但它似乎不起作用。 当我单击相机开关时,ICON 屏幕只是挂起,没有任何显示,而且有时它会意外工作所以最终我不得不跳转到这个原生 API 解决方案,它显示了下面的代码。 衷心感谢您的期待。
start()
if (window.stream)
console.log('found stream and clearing that', window.stream)
window.stream.getTracks().forEach(function(track)
track.stop()
)
const constraints =
video: true,
audio: false
return navigator.mediaDevices
.getUserMedia(constraints)
.then(this.gotStream)
.then(this.gotDevices)
.catch(this.handleError);
gotStream(stream)
window.stream = stream // make stream available to console
// video.srcObject = stream;
// Refresh button list in case labels have become available
console.log('enumerating media devices ')
return navigator.mediaDevices.enumerateDevices()
gotDevices(mediaDevices)
const availableVideoInputs, videoConstraints = this.state
mediaDevices.forEach(mediaDevice =>
// console.log(mediaDevice)
if (mediaDevice.kind === 'videoinput')
console.log('found new video input ', mediaDevice)
availableVideoInputs.push(
deviceId: mediaDevice.deviceId,
label: mediaDevice.label
)
// availableVideoInputs.push('mediaDevice.deviceId.availableVideoInputs.push(mediaDevice.deviceId)')
)
console.log('aggregated availableVideoInputs new ', availableVideoInputs)
if (availableVideoInputs.length > 0)
// there are accessible webcam
// setting first device as default to open
const tempVideoConstraint = ...videoConstraints
if (availableVideoInputs[0].deviceId)
console.log('availableVideoInputs[0] = ', availableVideoInputs[0])
tempVideoConstraint.deviceId = availableVideoInputs[0].deviceId
// console.log('putting tempVideoConstraint.facingMode ', tempVideoConstraint)
// if (availableVideoInputs[0].label.includes('back'))
// tempVideoConstraint.facingMode = exact: 'environment'
// else
// // it is now turn to set front active
// tempVideoConstraint.facingMode = 'user'
//
console.log('setting new video constrains ', tempVideoConstraint)
// this.setState(
// availableVideoInputs,
// // activeVideoInputID: availableVideoInputs[0].deviceId,
// // videoConstraints: tempVideoConstraint
// )
this.updateAvailableVideoStream(availableVideoInputs)
return Promise.resolve('done setting updateAvailableVideoStream')
else
// no webcam is available or accessible
console.error('ERR::VIDEO_STREAM_NOT_AVAILABLE')
updateAvailableVideoStream(availableVideoInputs)
this.setState( availableVideoInputs )
componentDidMount()
this.start()
.then(data =>
console.log('data ', data)
console.log('update state ', this.state)
this.setState(
videoConstraints:
...this.state.videoConstraints,
facingMode: 'user'
)
)
handleCameraSwitch()
const videoConstraints, availableVideoInputs, activeVideoInputID = this.state
console.log('current video constraints ', videoConstraints)
const tempVideoConstraint = ...videoConstraints
// now check if it is possible to change camera view
// means check for another webcam
console.log( availableVideoInputs )
console.log( activeVideoInputID )
console.log( remainingVideoStreams )
if (availableVideoInputs.length === 1)
// cannot change the webcam as there is only 1 webcam available
console.error('ERR - cannot change camera view [Available Video Inputs: 1]')
return
// now change the view to another camera
// get the current active video input device id and filter then from available video stream
const remainingVideoStreams = availableVideoInputs.filter(videoStream => videoStream.deviceId !== activeVideoInputID)
// now check if in remainingVideoStreams there is more than 1 stream available to switch
// if available then show the Stream Selection List to user
// else change the stream to remainingVideoStreams[0]
console.log( availableVideoInputs )
console.log( activeVideoInputID )
console.log( remainingVideoStreams )
if (remainingVideoStreams && remainingVideoStreams.length === 1)
tempVideoConstraint.deviceId = remainingVideoStreams[0].deviceId
console.log('new video constraints ', ...tempVideoConstraint)
console.log('webcam ref ', this.webCamRef.current)
// if (remainingVideoStreams[0].label.includes('back') || tempVideoConstraint.facingMode === 'user')
// tempVideoConstraint.facingMode = exact: 'environment'
// else
// // it is now turn to set front active
// tempVideoConstraint.facingMode = 'user'
//
console.log('new video constraints with facing mode', tempVideoConstraint)
// const constraints =
// video: tempVideoConstraint
//
// navigator.mediaDevices.getUserMedia(constraints)
// .then((stream) =>
// console.log('stream -> ', stream)
// )
// .catch((error) =>
// console.error('Some error occured while changing the camera view ', error)
// console.log(error)
// )
this.setState( videoConstraints: tempVideoConstraint, activeVideoInputID: remainingVideoStreams[0].deviceId )
else
// show the remaining stream list to user
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
【问题讨论】:
【参考方案1】:这是您的实现的小变化。 但这将完全符合您的期望。
请参阅下面的切换相机前/后的实现。 我还添加了错误验证,例如:
-
如果没有可用的视频流,则会抛出错误。
如果尝试访问后置摄像头时只有 1 个视频流可用,则会引发错误。
如果您有任何其他方法或想要更多说明,请点赞并回复评论
componentDidMount()
const gotDevices = (mediaDevices) =>
new Promise((resolve, reject) =>
const availableVideoInputs = []
mediaDevices.forEach(mediaDevice =>
if (mediaDevice.kind === 'videoinput')
availableVideoInputs.push(
deviceId: mediaDevice.deviceId,
label: mediaDevice.label
)
)
if (availableVideoInputs.length > 0)
resolve(availableVideoInputs)
else
reject(new Error('ERR::NO_MEDIA_TO_STREAM'))
)
navigator.mediaDevices.enumerateDevices().then(gotDevices)
.then((availableVideoInputs) => this.setState( availableVideoInputs ))
.catch((err) => this.setState( hasError: err ))
updateFileUploadView(newActiveView)
this.setState( activeFileUploadView: newActiveView )
const hasError = this.state
if (newActiveView === 'clickFromWebcam' && hasError)
return console.error(hasError)
if (newActiveView === '')
// means no view is active and clear the selected image
this.setState( captureImageBase64: '', videoConstraints: defaultVideoConstraints )
changeCameraView()
const availableVideoInputs = this.state
if (availableVideoInputs.length === 1)
return console.error('ERR::AVAILABLE_MEDIA_STREAMS_IS_1')
this.setState( resetCameraView: true )
setTimeout(() =>
const videoConstraints: facingMode = this.state
const newFacingMode = facingMode === 'user' ? exact: 'environment' : 'user'
this.setState(
videoConstraints: facingMode: newFacingMode ,
resetCameraView: false
)
, 100)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
!resetCameraView ?
<Webcam
audio=false
height='100%'
ref=this.webCamRef
screenshotFormat="image/png"
minScreenshotWidth=screenShotWidth
minScreenshotHeight=screenShotHeight
screenshotQuality=1
width='100%'
videoConstraints=videoConstraints
/>
: 'Loading...'
如您所见,此实现使用 react-webcam 库
在componentDidMount中,您将首先检查类型视频输入的可用媒体流,然后在其他方法中,例如更改cameraView,即将相机切换到前/后。
我仅卸载网络摄像头 100 毫秒,然后使用新的 videoConstraints 将其安装回来,无论是 facesMode: 'user' 还是 facesMode: exact: 'environment'
这种方法将为您的代码提供一个良好的开端,您可以玩转代码并从中获得乐趣。 谢谢!
【讨论】:
以上是关于无法使用 webrtc MediaDevices 在反应应用程序中切换摄像头(从前到后)的主要内容,如果未能解决你的问题,请参考以下文章