正确处理 React Hooks 以将摄像机流式传输到 HTML 视频元素

2024-01-02

我一直在尝试编写一个 React Hook 来处理从用户相机捕获的流式视频到 HTML 视频元素。我无法找到处理初始化和取消初始化相机和 HTML 视频元素的最佳方法。

我尝试在挂钩末尾添加清理功能,但我的尝试最终导致视频反复重新初始化或出现许多其他奇怪的错误。

确实,我正在努力弄清楚如何以及为何调用清理函数。它似乎与正在卸载的组件无关。

另外,我不确定如何最好地销毁视频,尽管这里已经有很多答案,但我不确定是否需要完全删除它。如果它挂在身边也没什么坏处,只有六页。我想我只是想在用户离开页面时停止摄像头流式传输,并在用户返回视频页面时再次启动摄像头流式传输。

相机视频流挂钩

import { useEffect, useState } from 'react';

const initialiseCamera = async() => await
    navigator
        .mediaDevices
        .getUserMedia({audio: false, video: true});

export const useCamera = videoRef => {
    const [isCameraInitialised, setIsCameraInitialised] = useState(false);
    const [video, setVideo] = useState(null);
    const [error, setError] = useState('');
    const [playing, setPlaying] = useState(true);

    useEffect(() => {
        if(video || !videoRef.current) {
            return;
        }

        const videoElement = videoRef.current;
        if(videoElement instanceof HTMLVideoElement) {
            setVideo(videoRef.current);
        }
    }, [videoRef, video]);

    useEffect(() => {
        if(!video || isCameraInitialised || !playing) {
            return;
        }

        initialiseCamera()
            .then(stream => {
                video.srcObject = stream;
                setIsCameraInitialised(true);
            })
            .catch(e => {
                setError(e.message);
                setPlaying(false);
            });
    }, [video, isCameraInitialised, playing]);

    useEffect(() => {
        const videoElement = videoRef.current;

        if(playing) {
            videoElement.play();
        } else {
            videoElement.pause();
        }

    },[playing, videoRef]);



    return [video, isCameraInitialised, playing, setPlaying, error];
};


视频观看

import React, {createRef} from 'react';
import { useCamera } from '../hooks/use-camera';
import { Button } from '@orderandchaos/react-components';

const VideoViewDemo = () => {
    const videoRef = createRef();
    const [video, isCameraInitialised, running, setPlaying, error] = useCamera(videoRef);

    return (
        <div>
            <video
                ref={videoRef}
                autoPlay={true}
                muted={true}
                controls
                width={480}
                height={270}
            />
            <Button
                onClick={() => setPlaying(!running)}
                ariaLabel='Start/Stop Audio'
            >{running ? 'Stop' : 'Start'}</Button>
        </div>
    );
};

export default VideoViewDemo;


如果您在任何 useEffect 中添加一个清理函数,该函数的参数被指定为依赖数组,则只要任何参数发生更改,清理函数就会运行。

为了使视频清理仅在卸载时运行,您必须传递一个空的依赖项数组。现在,由于效果内的变量将属于初始运行时的闭包,因此您需要有一个引用这些值的 ref 。

您可以编写一个清理钩子来处理这个问题

const useCleanup = (val) => {
    const valRef = useRef(val);
    useEffect(() => {
       valRef.current = val;
    }, [val])

    useEffect(() => {
        return () => {
              // cleanup based on valRef.current
        }
    }, [])
}



import { useEffect, useState } from 'react';

const initialiseCamera = async() => await
    navigator
        .mediaDevices
        .getUserMedia({audio: false, video: true});

export const useCamera = videoRef => {
    const [isCameraInitialised, setIsCameraInitialised] = useState(false);
    const [video, setVideo] = useState(null);
    const [error, setError] = useState('');
    const [playing, setPlaying] = useState(true);

    useEffect(() => {
        if(video || !videoRef.current) {
            return;
        }

        const videoElement = videoRef.current;
        if(videoElement instanceof HTMLVideoElement) {
            setVideo(videoRef.current);
        }
    }, [videoRef, video]);


    useCleanup(video)

    useEffect(() => {
        if(!video || isCameraInitialised || !playing) {
            return;
        }

        initialiseCamera()
            .then(stream => {
                video.srcObject = stream;
                setIsCameraInitialised(true);
            })
            .catch(e => {
                setError(e.message);
                setPlaying(false);
            });
    }, [video, isCameraInitialised, playing]);

    useEffect(() => {
        const videoElement = videoRef.current;

        if(playing) {
            videoElement.play();
        } else {
            videoElement.pause();
        }

    },[playing, videoRef]);



    return [video, isCameraInitialised, playing, setPlaying, error];
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

正确处理 React Hooks 以将摄像机流式传输到 HTML 视频元素 的相关文章

随机推荐

  • 如何提高Redis服务器的CPU使用率?

    我的目标是让我们的 Redis 服务器在生产中达到 80 左右的 CPU 利用率 这将有利于我们的后端服务器设计 确保我们不会充分利用 CPU 同时也为增长和峰值留出一些空间 在使用Redis自己的基准测试工具时redis benchmar
  • 在嵌套文件夹中查找文件[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 如何在嵌套文件夹中搜索文件 看看这个函数 System IO DirectoryInfo GetFiles SearchPattern
  • 如何检查我的应用程序从磁盘写入和读取了多少字节?

    我不知道我是否没有使用正确的词在网络上搜索 但我没有找到解决方案来查看我的应用程序已经在磁盘上读取和写入了多少 有人可以帮我解决这个问题吗 tks 解决 如果有人需要功能标志 type IO COUNTERS record ReadOper
  • 如何获取当前页面的html?

    我想解析当前页面的html 如何在asp net中获取当前页面的html 提前致谢 对于客户端 在互联网浏览器中 右键点击浏览器 gt 查看源代码 在火狐浏览器中 右键点击浏览器 gt 查看页面源代码 对于服务器端 您可以重写页面的渲染方法
  • 尝试在路径 file:///var/mobile/Media/PhotoData/Photos.sqlite 添加只读文件?

    我刚刚更新到新的 Xcode beta 6 0 当尝试使用 iOS 8 为 ipad mini 进行编译时 我在控制台中收到一个奇怪的错误 尝试在路径 file var mobile Media PhotoData Photos sqlit
  • JTextPane 换行行为

    最近我一直在做一个Java文本编辑器项目 我想使用JTextPane更换旧的JTextArea以实现语法高亮 然而 一个JTextPane缺乏方法JTextArea 例如append getLineStartOffset 等 我想在我的课堂
  • 如何在 Spark 2.0 中启用笛卡尔连接? [复制]

    这个问题在这里已经有答案了 我必须在 Spark 2 0 中交叉连接 2 个数据帧 但遇到以下错误 用户类抛出异常 org apache spark sql AnalysisException Cartesian joins could b
  • 序列化器仅来自指定控制器的方法 - Spring、JSON Jackson

    我有 2 个控制器和一个具有自定义序列化字段的 get 方法 如下所示 JsonSerialize using MySerialization class 但我想在我从 A 控制器而不是 B 控制器调用方法时进行此序列化 我如何指定这一点
  • 使用 JUnit 内部类中的测试用例

    我读到构建单元测试 http haacked com archive 2012 01 02 structuring unit tests aspx每个类都有一个测试类 每个方法有一个内部类 我认为这似乎是一种组织测试的便捷方法 因此我在 J
  • 当从两个数据框构建绘图时有两个图例

    我有两个这样的数据框 library ggplot2 set seed 1 x1 rnorm 100 y1 rnorm 100 x2 rnorm 100 y2 rnorm 100 df1 data frame x x1 y y1 col1
  • 在 pdfmake 中嵌入背景图像

    我正在使用 pdfmakehttp bpampuch github io pdfmake index html gettingstarted http bpampuch github io pdfmake index html gettin
  • JavaPackage 对象不可调用错误:Pyspark

    像 dataframe show sqlContext read json 这样的操作工作正常 但大多数函数都会给出 JavaPackage object is not callable error 例如 当我这样做时 dataFrame
  • 当应用程序进入前台时查找当前视图。 IOS

    当应用程序激活时 我们如何找到当前哪个视图是第一响应者 我知道应用程序委托 applicationWillEnterForeground 和 applicationDidBecomeActive 在某些情况下将被调用 我如何使用它来亲密查看
  • django 模板中的 user.is_authenticated 遇到问题

    很抱歉 如果您在我之前问这个问题时尝试帮助我 不得不删除该问题 因为由于某种原因我不被允许编辑其他信息 我正在努力在我的 Django 网站上实现用户身份验证 一切正常 我的视图 模型 url 等都设置好了 用户可以注册 登录 注销 我遇到
  • 将 MarvinFramework 添加到 Tomcat7 上的 Web 应用程序

    我有一个JerseyWeb 应用程序运行于Tomcat并想要整合MarvinFramework用于图像处理 基本上我想减少噪音 灰度和缩放图像以进行进一步处理 The 马文框架 http marvinproject sourceforge
  • Cmder bash脚本执行

    我在 Windows 中创建了基本脚本 bin bash echo Hello 我正在使用 Cmder ConEmu 衍生品 我尝试使用 chmod 更改权限 但它们是相同的 我不知道如何执行这个脚本 正常的 Linux 方式是 hello
  • R 编译错误的 RGL 包

    尝试在 arch linux x86 64 上为 r 编译 rgl 我只复制了安装的错误部分 这是我最近更新 R 后发生的 知道如何解决这个问题吗 g I usr include R DNDEBUG DHAVE PNG H I usr in
  • 按位置列出观测值数量

    这里需要帮助 我正在尝试创建一个新列 使用纬度和经度列出餐厅 200 米范围内的餐厅数量 我在 stackoverflow 上找不到任何东西 而且我不是 R 忍者 任何帮助 将不胜感激 head business id restaurant
  • 带有azure ad的net core使用oidc和登录后浏览器后退按钮导致异常

    因此 我有一个新创建的 netcore 应用程序链接到我的 azure Active Directory 帐户 中间件设置如下 app UseCookieAuthentication new CookieAuthenticationOpti
  • 正确处理 React Hooks 以将摄像机流式传输到 HTML 视频元素

    我一直在尝试编写一个 React Hook 来处理从用户相机捕获的流式视频到 HTML 视频元素 我无法找到处理初始化和取消初始化相机和 HTML 视频元素的最佳方法 我尝试在挂钩末尾添加清理功能 但我的尝试最终导致视频反复重新初始化或出现