Skip to content

[devOps] Error: "n.videoElt.captureStream is not a function" in SafariΒ #626

@ccarse

Description

@ccarse

Dear ml5 community,

I'm submitting a new issue. Please see the details below.

β†’ Step 1: Describe the issue πŸ“

Did you find a bug? Want to suggest an idea for feature?
I'm receiving the following bug when trying to use the YOLO model in Safari:

Unhandled Promise Rejection: TypeError: n.videoElt.captureStream is not a function. (In 'n.videoElt.captureStream()', 'n.videoElt.captureStream' is undefined)
dispatchException β€” runtime.js:569

It looks like captureStream isn't supported in Safari? Is there an alternative api I can use?

Here's my code:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
const ml5 = require('ml5');

interface SmartCameraState {
  isLoading: boolean;
  results: string;
  width: number;
  height: number;
}

export class SmartCamera extends React.Component<{}, SmartCameraState> {
  videoRef?: HTMLVideoElement;
  canvasRef?: HTMLCanvasElement;

  detector?: any;

  constructor(props: {}) {
    super(props);
    this.state = {
      isLoading: true,
      results: '',
      width: 640,//1280,
      height: 480//960
    };
  }

  async componentDidMount() {
    if (!this.videoRef || !this.canvasRef) { return; }

    const ctx = this.canvasRef.getContext('2d') as CanvasRenderingContext2D;
    ctx.lineWidth = 5;
    ctx.strokeStyle = "#FFFFFF";
    ctx.font = '20px Arial';
    ctx.textBaseline = 'top';

    // Create a webcam capture
    const stream = await navigator.mediaDevices.getUserMedia({ video: { width: this.state.width, height: this.state.height, facingMode: 'environment'} });
    console.log('Camera loaded');
    this.videoRef.srcObject = stream;
    await this.videoRef.play();

    const classifyVideo = () => {
      this.detector.detect(gotResult);
    }

    const gotResult = (err: any, results: {label: string, confidence: number, x: number, y: number, w: number, h: number}[]) => {
      if (this.state.isLoading) { this.setState({isLoading: false}); }

      ctx.clearRect(0, 0, this.state.width, this.state.height);
      results.forEach(result => {
        const resultStr = `${result.label} ${(result.confidence * 100).toFixed(1)}%`;
        const xpos = this.state.width * result.x;
        const ypos = this.state.height * result.y;
        const boxWidth = this.state.width * result.w;
        const boxHeight = this.state.height * result.h;
        const textWidth = ctx.measureText(resultStr).width;
        // console.log(`x: ${xpos} y: ${ypos} w: ${boxWidth} h: ${boxHeight}`);

        ctx.beginPath();
        ctx.rect(xpos, ypos, boxWidth, boxHeight);
        ctx.stroke();
        ctx.fillStyle = "#FFFFFF";
        ctx.fillRect(xpos, ypos, textWidth, 22);
        ctx.fillStyle = "#000000";
        ctx.fillText(resultStr, xpos, ypos);
      });

      // this.setState({results: JSON.stringify(results, null, 2)});
      classifyVideo();  
    }

    this.videoRef.
    this.detector = await ml5.YOLO(this.videoRef, () => classifyVideo());
    // classifyVideo();
  }
  
  render() {
    return (
      <>
        {this.state.isLoading ? <div>loading...</div> : null}
        <div>
          <video id="video" autoPlay muted loop playsInline ref={this.setVideoInputRef} width={this.state.width} height={this.state.height} style={{position: 'fixed'}}/>
          <canvas width={this.state.width} height={this.state.height} ref={ ref => ref && (this.canvasRef = ref)} style={{position: 'fixed'}}/>
        </div>
      </>
    );
  }

  setVideoInputRef = (ref: HTMLVideoElement) => {
    ref && (this.videoRef = ref) 
  }
}

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions