Невозможно переключить камеру (спереди назад) в приложении реагирования, используя webrtc MediaDevices - PullRequest
2 голосов
/ 05 марта 2019

Это пример демонстрации того, что я собирался сделать. Если у кого-то есть идеи об этом исправлении, чтобы заставить его работать или какая-либо новая логика, пожалуйста, поделитесь.

Эта демонстрация реализована с использованием mediaStream API и используя библиотеку реагирующих веб-камер, которая фактически дает возможность управлять видом камеры с помощью реквизита с именем videoConstraints = {ringMode: 'user' или 'environment'}, но, похоже, это не работает. когда я щелкаю по значку переключателя камеры, экран просто зависает и ничего не отображается, а иногда и неожиданно работает. Так что в конечном итоге мне пришлось перейти на это нативное 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 Ответ

2 голосов
/ 05 марта 2019

Это небольшой вариант вашей реализации.Но это будет работать именно так, как вы хотели.

Пожалуйста, ознакомьтесь с приведенной ниже реализацией для переключения камеры вперед / назад.Я также добавил проверку ошибок, например:

  1. Будет выдано сообщение об ошибке, если видеопоток недоступен.
  2. Будет выдано сообщение об ошибке, если при наличии только 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...'

Как вы можете видеть, эта реализация использует библиотеку реагирующих веб-камер

в componentDidMount сначала вы проверите доступный медиа-поток типа видеовхода , а затем другими способами, такими как изменение cameraView, т. Е. Переключение камеры вперед / назад.

Я отключаю веб-камерутолько на 100 мс, а затем смонтируйте его снова с новыми videoConstraints либо {ringMode: 'user'} или {сторонойMode: {точный: 'среда'}}

Этот подход даст вашему коду преимущество, и вы сможете поиграть с кодом и повеселиться. Спасибо!

...