mozmorris / react-webcam

Webcam component
https://codepen.io/mozmorris/pen/JLZdoP
MIT License
1.63k stars 281 forks source link

react-webcam not working in some device like this SM-A605G , M2102J20SG #405

Open aligprr opened 1 month ago

aligprr commented 1 month ago

user click start button and record video start but when countdown complete i call handleStop function for stop record but onCapture not call fo send video to my service

this is my code =>

import Webcam from "react-webcam"; import {useRef, useState} from "react"; import React from "react" import {blobToBase64} from "../tools/helpers"; import {useStreamManager} from "../tools/contexts/StreamManager"; import {BsCameraVideoOff} from "react-icons/bs"; import Spinner from "./Spinner"; import BottomButtonWrapper from "./BottomButtonWrapper"; import Button from "./Button"; import {BiChevronRight} from "react-icons/bi"; import {FaQuestionCircle} from "react-icons/fa"; import Countdown from "react-countdown";

const VideoCamera1 = ({max, title, handleShowGuid, hasBack, onBack, onCapture, webcamRef, faceMode = 'environment'}) => { const {startStream} = useStreamManager(); const [start, setStart] = useState(false); const clockRef = useRef(); const mediaRecorderRef = React.useRef(null); const [recordedChunks, setRecordedChunks] = React.useState([]); const [isLoading, setLoading] = useState(true); const [cameraError, setCameraError] = useState(null); const handleDownload = React.useCallback(() => { if (recordedChunks.length) { const blob = new Blob(recordedChunks, { type: faceMode ? "video/mp4" : "video/webm" }); blobToBase64(blob).then(res => { onCapture(res);

        });

        setRecordedChunks([]);
    }
}, [recordedChunks]);
const handleDataAvailable = React.useCallback(
    ({data}) => {
        if (data.size > 0) {
            setRecordedChunks((prev) => prev.concat(data));
        }
    },
    [setRecordedChunks]
);
const handleStopCaptureClick = React.useCallback(() => {

    if (mediaRecorderRef?.current?.state === 'inactive') return
    if (mediaRecorderRef?.current?.state === "recording") {
        mediaRecorderRef?.current?.stop();
    }

}, [mediaRecorderRef]);
const handleStartCaptureClick = React.useCallback(() => {

    const stream = webcamRef.current.video.srcObject;
    try {
        mediaRecorderRef.current = new MediaRecorder(stream, {
            mimeType: "video/webm"
        });
        mediaRecorderRef.current.addEventListener(
            "dataavailable",
            handleDataAvailable
        );
        mediaRecorderRef.current.start();

    } catch (e) {

        try {

            mediaRecorderRef.current = new MediaRecorder(stream, {
                mimeType: 'video/mp4',
                videoBitsPerSecond: 100000
            });
            mediaRecorderRef.current.addEventListener(
                "dataavailable",
                handleDataAvailable
            );
            mediaRecorderRef.current.start();
        } catch (err2) {
            // If fallback doesn't work either. Log / process errors.
            console.error({e});
            console.error({err2})
        }
    }

}, [webcamRef, handleDataAvailable, mediaRecorderRef]);

const handleStart = () => {
    setStart(true)
    clockRef.current.start();
    handleStartCaptureClick()
};

const handleStop=()=>{ setStart(false) clockRef.current.stop(); handleStopCaptureClick(); }

React.useEffect(() => {
    if (recordedChunks.length > 0) {
        handleDownload();
    }

}, [handleDownload, recordedChunks]);
const renderer = ({hours, minutes, seconds, completed}) => {
    if(!start){
        return <></>
    }
    if (completed) {
        return <span>finished</span>;
    } else {
        return (
            <span className="w-full flex justify-between items-center">

                    <span>recording</span>
                    <span>{hours}:{minutes}:{seconds}</span>
                 </span>
        );
    }
};

return <div className="w-full flex justify-center items-center flex-col">
    <div className="flex justify-center w-full mb-5  flex flex-col items-center pt-4">
        {!isLoading && !cameraError && <div
            className={`flex justify-center ${(hasBack || title) ? ' border-b' : ''} pb-5  items-center w-full ${hasBack ? 'justify-between' : 'justify-center'}`}>
            {hasBack && <BiChevronRight className="text-xl  " onClick={onBack}/>}
            <strong className="text-lg flex justify-center items-center gap-2 "><span>{title}</span>
                <FaQuestionCircle onClick={handleShowGuid} className="text-blue-400 "/></strong>
            {hasBack && <BiChevronRight className="text-xl  opacity-0"/>}
        </div>}
        {/*{!isLoading && !cameraError && text && <p className="text-center text-sm mb-2  text-gray-800">{text}</p>}
        {!isLoading && !cameraError &&text2 && <p className="text-center font-bold mb-5 text-sm  rounded text-green-500 ">"{text2}"</p>}*/}
        <div className="relative mt-5">
            {!isLoading && !cameraError &&
                <svg className="absolute center-guide-face" xmlns="http://www.w3.org/2000/svg" width="97"
                     height="132" viewBox="0 0 194 265">
                    <g id="Ellipse_1" data-name="Ellipse 1" fill="none" stroke="#32bc89" strokeWidth="8"
                       strokeDasharray="3 10">
                        <ellipse cx="97" cy="132.5" rx="97" ry="132.5" stroke="none"/>
                        <ellipse cx="97" cy="132.5" rx="93" ry="128.5" fill="none"/>
                    </g>
                </svg>}
            <Webcam
                audio={true}
                height={480}
                width={480}
                muted={true}
                audioConstraints={{
                    echoCancellation: true,
                    noiseSuppression: true,
                }}

                onUserMedia={(stream) => {
                    setCameraError(null)
                    setLoading(false)
                    startStream(stream)
                }}
                onUserMediaError={(error) => {
                    if (error.toString().includes('dismissed')) {
                        setCameraError('error dismissed.')
                    } else if (error.toString().includes('denied')) {
                        setCameraError(error denied.')
                    } else if (error.toString().includes('Requested device not found')) {
                        setCameraError('error not found.')
                    }
                    setLoading(false)
                }}
                style={{objectFit: "cover"}}
                className="rounded-full  w-56 h-56"
                mirrored={false}

                videoConstraints={{
                    faceMode,
                    screenshotQuality: 1,
                    aspectRatio: 1,
                    width: {min: 480, ideal: 480},
                    height: {min: 480, ideal: 480}
                }}
                ref={webcamRef}
            />
        </div>

    </div>
    {isLoading && <div className="flex justify-center items-center flex-col">
        <Spinner className="text-lg text-green-500"/>

    </div>}
    {cameraError && <div
        className="w-full  rounded-lg   text-center  p-5 text-red-500  mx-auto flex flex-col justify-center  items-center  flex justify-center items-center">
        <BsCameraVideoOff className="text-5xl text-red-500"/>
        <p className=" mt-5 w-full text-center">{cameraError}</p>
    </div>}
    {!isLoading && !cameraError &&
        <BottomButtonWrapper grid={1} className="flex   justify-center w-full items-center  z-20    mt-5 left-0">

            <Button
                disabled={start}
                rounded="rounded-lg"
                theme={start ? "red" : "green"}
                className="z-20 p-3 w-full   transition duration-200  "
                onClick={handleStart}>
                {<Countdown
                    autoStart={false}
                    ref={clockRef}

                    onComplete={handleStop}
                    date={Date.now() + max*1000} // 10 seconds countdown
                    renderer={renderer}
                />  }
                {!start && "start"}
            </Button>
        </BottomButtonWrapper>}

</div>

} export default VideoCamera1