Search code examples
vue.jsvideo-streaminghtml5-videovuejs3

Binding A Media Feed/ Stream to Video Element - Vue 3 Composition API


I am trying to bind a camera feed to a video element using Vue 3, but I can not seem to even get a basic example working. Can someone tell me what I am missing?

import { ref, reactive } from 'vue'
let stream: any = reactive({})
let constraints = {
    audio: false,
    video: {
      width: { min: 1024, ideal: 1280, max: 1920 },
      height: { min: 576, ideal: 720, max: 1080 },
      facingMode: 'environment'
    }
  }
stream = await navigator.mediaDevices.getUserMedia(constraints)

Then in my template I have tried both of the following ways to bind

<video :srcObject.prop="stream" width="300" height="200" autoplay></video>
<video :srcObject.prope.camel="stream" autoplay playsinline></video>

Solution

  • Your code overwrites stream with the result of getUserMedia(), which effectively removes the original reactive() instance from the component's context.

    Solution

    Make stream a ref instead of reactive, and set its value property to the result of getUserMedia().

    Also, to ensure the user's resources are activated only when necessary, call getUserMedia() in the component's mounted hook, and stop the stream in the beforeUnmount hook.

    <script setup>
    import { ref, onMounted, onBeforeUnmount } from 'vue'
    
    const stream = ref(null)
    const constraints = {
      audio: false,
      video: {
        width: { min: 1024, ideal: 1280, max: 1920 },
        height: { min: 576, ideal: 720, max: 1080 },
        facingMode: 'environment',
      },
    }
    
    onMounted(async () => {
      stream.value = await navigator.mediaDevices.getUserMedia(constraints)
    })
    
    onBeforeUnmount(() => {
      stream.value.getTracks().forEach(track => track.stop())
    })
    </script>
    
    <template>
      <video :srcObject="stream" width="300" height="200" autoplay></video>
    </template>
    

    demo