在javascript中获取视频第一帧

发布于 2024-07-29 02:50:34 字数 38 浏览 2 评论 0原文

如何在 javascript 中获取视频文件的第一帧作为图像?

How can I get the first frame of a video file in javascript as an image?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

北渚 2024-08-05 02:50:34

可以使用 HTML 5 视频和画布标签来完成:

HTML:

<input type="file" id="file" name="file">

<video id="main-video" controls>
   <source type="video/mp4">
</video>

<canvas id="video-canvas"></canvas>

Javascript:

var _CANVAS = document.querySelector("#video-canvas");
var _CTX = _CANVAS.getContext("2d");
var _VIDEO = document.querySelector("#main-video");

document.querySelector("#file").addEventListener('change', function() {

    // Object Url as the video source
    document.querySelector("#main-video source").setAttribute('src', URL.createObjectURL(document.querySelector("#file").files[0]));

    // Load the video and show it
    _VIDEO.load();

    // Load metadata of the video to get video duration and dimensions
    _VIDEO.addEventListener('loadedmetadata', function() {
        // Set canvas dimensions same as video dimensions
        _CANVAS.width = _VIDEO.videoWidth;
        _CANVAS.height = _VIDEO.videoHeight;
    });

    _VIDEO.addEventListener('canplay', function() {
        _CANVAS.style.display = 'inline';
        _CTX.drawImage(_VIDEO, 0, 0, _VIDEO.videoWidth, _VIDEO.videoHeight);
    });

});

查看演示

It can be done with HTML 5 video and canvas tags:

HTML:

<input type="file" id="file" name="file">

<video id="main-video" controls>
   <source type="video/mp4">
</video>

<canvas id="video-canvas"></canvas>

Javascript:

var _CANVAS = document.querySelector("#video-canvas");
var _CTX = _CANVAS.getContext("2d");
var _VIDEO = document.querySelector("#main-video");

document.querySelector("#file").addEventListener('change', function() {

    // Object Url as the video source
    document.querySelector("#main-video source").setAttribute('src', URL.createObjectURL(document.querySelector("#file").files[0]));

    // Load the video and show it
    _VIDEO.load();

    // Load metadata of the video to get video duration and dimensions
    _VIDEO.addEventListener('loadedmetadata', function() {
        // Set canvas dimensions same as video dimensions
        _CANVAS.width = _VIDEO.videoWidth;
        _CANVAS.height = _VIDEO.videoHeight;
    });

    _VIDEO.addEventListener('canplay', function() {
        _CANVAS.style.display = 'inline';
        _CTX.drawImage(_VIDEO, 0, 0, _VIDEO.videoWidth, _VIDEO.videoHeight);
    });

});

View demo

错爱 2024-08-05 02:50:34

只需将视频标签添加到页面中,没有控件,也不会自动播放。

<代码>
<视频宽度=“96”高度=“54”类=“剪辑缩略图”> ...
缺点

是用户可以通过右键单击缩略图并在上下文菜单中选择“播放”来播放视频。 为了避免这种情况,您需要一些 JavaScript 来监听点击事件并取消它们(从缩略图中删除上下文菜单)。

Just add the video tag to the page with no controls and no auto-play.


<video width="96" height="54" class="clip-thumbnail"> ... </video>

Drawback is that users can play the video by right clicking the thumbnail and selecting "play" in the context-menu. To avoid that you'd need a little javascript listening for click events and cancelling them (removing context-menu from thumbnails).

烟雨扶苏 2024-08-05 02:50:34

如前所述,Javascript 无法做到这一点。

如果您想为视频创建缩略图,则必须创建缩略图服务器端,然后像处理任何其他图像一样在客户端上提供图像。

我选择的实现此目的的方法是 ffmpeg 解码器。 它可以处理多种文件格式,并且能够执行您想要的操作。 因此,如果您有一个名为 hello.avi 的视频,您可能会这样做:

ffmpeg -itsoffset -1 -i /path/to/hello.avi -vcodec mjpeg -vframes 1 -an -f rawvideo -s 200x150 /path/to/hello.jpg

您可以使用您正在使用的任何服务器端语言运行此命令(修复路径和尺寸...),它将创建视频文件的缩略图。

As mentioned, Javascript is not able to do this.

If you want to create thumbnails for your videos you have to create the thumbnail server side and then simply serve up the image on the client as you would any other image.

My method of choice for accomplishing this is the ffmpeg decoder. It can handle a multitude of file formats and is able to do what you want. So if you have a video named hello.avi, you might do:

ffmpeg -itsoffset -1 -i /path/to/hello.avi -vcodec mjpeg -vframes 1 -an -f rawvideo -s 200x150 /path/to/hello.jpg

You can run this command (fixing the paths and dimensions...) with whatever server-side language you are using and it would create a thumbnail of the video file.

瞳孔里扚悲伤 2024-08-05 02:50:34

如果视频是用户在 中选择的文件,您可以使用 FileReader API 获取 base-64 视频数据:

https://developer.mozilla.org/en-US/docs/DOM/FileReader

从那里你只剩下一个极其棘手的问题:解码视频并以某种方式在 JavaScript 中挑选并渲染单个帧。 或者,您可以将整个视频作为“缩略图预览”(我想这就是您这样做的原因?),如下所示:

http://hacks.mozilla.org/2009/12/file-drag-and-drop-in-firefox- 3-6/

不过,不确定最后一个示例的兼容性,或者它与较大视频文件的配合效果如何(我听说您很容易遇到 URL 长度限制)

It may be possible if the video is a file selected by the user into an <input type="file">, you can get the base-64 video data using the FileReader API:

https://developer.mozilla.org/en-US/docs/DOM/FileReader

From there you're just left with the extremely intractable problem of decoding the video and somehow picking out and rendering a single frame, in javascript. Alternatively, you could just include the entire video as the "thumbnail preview" (I assume that's why you're doing this?), as demonstrated here:

http://hacks.mozilla.org/2009/12/file-drag-and-drop-in-firefox-3-6/

Not sure about the compatability of that last example though, or how well it work with larger video files (I hear you can easily bump up against URL length restrictions)

屋顶上的小猫咪 2024-08-05 02:50:34

您可以使用 canvas API 来实现此目的。

创建以下函数
这将为指定的帧生成一个 png 文件。

export const videoToImage = (
    videoFile: File,
    options: { 
        frameTimeInSeconds?: number
        filename?: string
        extension?: string 
    } = { 
        frameTimeInSeconds: 0.5, 
        extension: "png" 
    }
): Promise<File> => {
    return new Promise<File>((resolve) => {
        const canvas = document.createElement('canvas')
        const video = document.createElement('video')
        const source = document.createElement('source')
        const context = canvas.getContext('2d')
        const urlRef = URL.createObjectURL(videoFile)

        video.style.display = 'none'
        canvas.style.display = 'none'

        source.setAttribute('src', urlRef)
        video.setAttribute('crossorigin', 'anonymous')
        video.setAttribute('preload', 'metadata')

        video.appendChild(source)
        document.body.appendChild(canvas)
        document.body.appendChild(video)

        if (!context) {
            return
        }

        video.currentTime = options.frameTimeInSeconds
        video.load()

        video.addEventListener('loadedmetadata', function () {
            canvas.width = video.videoWidth
            canvas.height = video.videoHeight
        })

        video.addEventListener('loadeddata', function () {
            setTimeout(() => {
                context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight)

                canvas.toBlob((blob) => {
                    if (!blob) return
                    resolve(
                        new File([blob], (options.filename || videoFile.name) + "_preview."+options.extension, { 
                            type: 'image/' + options.extension 
                        })
                    )
                    URL.revokeObjectURL(urlRef)
    
                    video.remove()
                    canvas.remove()
                }, 'image/' + options.extension)
            }, 2000)
        })
    })
}

用法:

videoToImage(videoFile).then((image: File) => {
    console.log(image)
})

描述:
此函数接收视频文件并创建加载视频源的画布以拍摄其内容的快照并生成新的 png 文件。

OBS:
需要延迟才能在移动设备上实现此功能。

You can achieve this using canvas API.

Create the following function:
This will generate a png file for the specified frame.

export const videoToImage = (
    videoFile: File,
    options: { 
        frameTimeInSeconds?: number
        filename?: string
        extension?: string 
    } = { 
        frameTimeInSeconds: 0.5, 
        extension: "png" 
    }
): Promise<File> => {
    return new Promise<File>((resolve) => {
        const canvas = document.createElement('canvas')
        const video = document.createElement('video')
        const source = document.createElement('source')
        const context = canvas.getContext('2d')
        const urlRef = URL.createObjectURL(videoFile)

        video.style.display = 'none'
        canvas.style.display = 'none'

        source.setAttribute('src', urlRef)
        video.setAttribute('crossorigin', 'anonymous')
        video.setAttribute('preload', 'metadata')

        video.appendChild(source)
        document.body.appendChild(canvas)
        document.body.appendChild(video)

        if (!context) {
            return
        }

        video.currentTime = options.frameTimeInSeconds
        video.load()

        video.addEventListener('loadedmetadata', function () {
            canvas.width = video.videoWidth
            canvas.height = video.videoHeight
        })

        video.addEventListener('loadeddata', function () {
            setTimeout(() => {
                context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight)

                canvas.toBlob((blob) => {
                    if (!blob) return
                    resolve(
                        new File([blob], (options.filename || videoFile.name) + "_preview."+options.extension, { 
                            type: 'image/' + options.extension 
                        })
                    )
                    URL.revokeObjectURL(urlRef)
    
                    video.remove()
                    canvas.remove()
                }, 'image/' + options.extension)
            }, 2000)
        })
    })
}

Usage:

videoToImage(videoFile).then((image: File) => {
    console.log(image)
})

Description:
This function receives a video file and creates a canvas loading the video source to take a snapshot of its contents and generate a new png file.

OBS:
Delay is required to make this work on mobile devices.

枉心 2024-08-05 02:50:34

JavaScript 无法做到这一点。

Javascript is not capable of doing this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文