微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ExpressJS 视频流有烦人的音频问题

如何解决ExpressJS 视频流有烦人的音频问题

我一直在尝试运行一个 Expressjs Web 服务器,该服务器从我的文件系统中提供视频。出于某种原因,每当播放视频时,都会有不断的爆裂声,最终(3-10 分钟后)音频完全中断。重新加载页面将恢复音频,但不会停止弹出。

我有 2 种不同的视频播放方法,但在运行时只使用了 1 种方法。它们都用于此功能

app.get(`/${VIDTYPE}/:path`,(req,res) => {
    let p = decode(req.params.path)
    let dir = path.dirname(p)
    let name = path.parse(p).name
    let ext = '.vtt'

    let track = path.resolve(`${dir}/${name}${ext}`)

    console.log({track})

    res.send(
        `<video id="videoplayer" controls width="90%" height="90%">` +
        `<source src="/video/${req.params.path}"/>` +
        `<track default kind="subtitles" label="en" src="/track/${encode(track)}"/>` +
        `</video>`
    )
})

第一种方法是从网上抄来的,感觉比较复杂。

app.get("/video/:path",res) => {
    let decoded = decode(req.params.path)
    console.log("video",{decoded})
    let stat = fs.statSync(decoded)
    let fileSize = stat.size
    let range = req.headers.range

    if (range) {
        const parts = range.replace(/bytes=/,"").split("-")
        const start = parseInt(parts[0],10)
        const end = parts[1] 
            ? parseInt(parts[1],10)
            : fileSize-1
        const chunksize = (end-start)+1
        const file = fs.createReadStream(decoded,{start,end})
        const head = {
            'Content-Range': `bytes ${start}-${end}/${fileSize}`,'Accept-Ranges': 'bytes','Content-Length': chunksize,'Content-Type': 'video/mp4',}
        res.writeHead(206,head);
        file.pipe(res);
    } else {
        const head = {
            'Content-Length': fileSize,}
        res.writeHead(200,head)
        fs.createReadStream(path).pipe(res)
    }
})

第二种方法要简单得多,而且功能似乎相同。它们都存在音频问题,但质量没有明显差异。

app.get("/video2/:path",res) => {
    res.sendFile(decode(req.params.path))
})

完整的代码库将在评论中。所有 mp4 文件都是使用 ffmpeg 从 mkv 转换而来的,因此这可能会导致问题,但在直接播放时,没有一个视频具有相同的音频问题。我也将问题隔离到移动设备上。

对我哪里出错有什么想法吗?

解决方法

代码库:

const { json } = require('body-parser')
const { dir } = require('console')
const { response } = require('express')
const express = require('express')
const fs = require("fs")
const path = require("path")

const port = 80

const app = express()

const vid_ext = [
    '.mp4','.webm'
]

const VIDTYPE = "vid"
const DIRTYPE = "dir"

const getAllFiles = function(dirPath) {
    console.log({dirPath});
    files = fs.readdirSync(dirPath)

    arrayOfFiles = [{
        path: path.join(dirPath + "/.."),title: "go up(beta)",type: DIRTYPE
    }]

    files.forEach(function(file) {
        let p = path.resolve(path.join(dirPath,"/",file))
        if (fs.statSync(dirPath + "/" + file).isDirectory()) {
            arrayOfFiles.push({ 
                path: p,title: file,type: DIRTYPE
            })
        } else {
            if (vid_ext.includes(path.extname(p))) {
                arrayOfFiles.push({
                    path: p,type: VIDTYPE
                })
            }
        }
    })

    return arrayOfFiles
}

app.get('/',(request,response) => {
    response.redirect(`/${DIRTYPE}/${encode("../stuff")}`);
});

app.get(`/${DIRTYPE}/:path`,(req,res) => {
    let decoded = decode(req.params.path)
    console.log(DIRTYPE,decoded)

    res.send(dirtable(decoded))
})

app.get("/video/:path",res) => {
    let decoded = decode(req.params.path)
    console.log("video",{decoded})
    let stat = fs.statSync(decoded)
    let fileSize = stat.size
    let range = req.headers.range

    if (range) {
        const parts = range.replace(/bytes=/,"").split("-")
        const start = parseInt(parts[0],10)
        const end = parts[1] 
            ? parseInt(parts[1],10)
            : fileSize-1
        const chunksize = (end-start)+1
        const file = fs.createReadStream(decoded,{start,end})
        const head = {
            'Content-Range': `bytes ${start}-${end}/${fileSize}`,'Accept-Ranges': 'bytes','Content-Length': chunksize,'Content-Type': 'video/mp4',}
        res.writeHead(206,head);
        file.pipe(res);
    } else {
        const head = {
            'Content-Length': fileSize,}
        res.writeHead(200,head)
        fs.createReadStream(path).pipe(res)
    }
})

app.get("/video2/:path",res) => {
    res.sendFile(decode(req.params.path))
})

app.get(`/${VIDTYPE}/:path`,res) => {
    let p = decode(req.params.path)
    let dir = path.dirname(p)
    let name = path.parse(p).name
    let ext = '.vtt'

    let track = path.resolve(`${dir}/${name}${ext}`)

    console.log({track})

    res.send(
        `<video id="videoplayer" controls width="90%" height="90%">` +
        `<source src="/video/${req.params.path}"/>` +
        `<track default kind="subtitles" label="en" src="/track/${encode(track)}"/>` +
        `</video>`
    )
    //res.redirect(`/video2/${req.params.path}`)
})

app.get("/track/:path",res) => {
    res.sendFile(decode(req.params.path))
})

function dirtable(a) {
    let files = getAllFiles(a)

    return (
        "<table><tbody>" + 
        files.map(x => `<td>${linkfrom(x)}</td><td>${x.type}</td>`).reduce((acc,x) => acc + `<tr>${x}</tr>`) +
        "</tbody></table>"
    )
}

function linkfrom(a) {
    return `<a href="/${a.type}/${encode(a.path)}">${a.title}</a>`
}

function encode(h) {
    return Buffer.from(h).toString('base64')
}

function decode(h) {
    return Buffer.from(h,"base64").toString()
}

app.listen(port,console.log(`App Listening to port ${port}`));

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。