跳到主要内容

视频上传与播放流程

文件上传步骤

前端上传

  1. 通过<input type="file">标签选择要上传的文件。

  2. 获取到input.files[0]就是选中的File对象。

  3. File对象放入FormData中,通过POST请求发送给后端。

    如果文件较大,可以在前端对文件进行切片处理:

    const file = input.files[0];
    const chunkSize = 2 * 1024 * 1024; // 2MB
    let cur = 0;
    while (cur < file.size) {
    // 切割文件
    const chunk = file.slice(cur, cur + chunkSize);
    cur += chunkSize;
    // 转成blob对象
    const chunkBlob = new Blob([chunk]);
    // 放入FormData
    formData.append('chunk', chunkBlob);
    }

后端处理

  1. 后端接收到FormData数据后,会获得文件的sizenametype等信息,以及文件的二进制内容。将文件内容存储到服务器的某个目录下,如backend_folder

    如果前端传来的是切片,后端需要对切片进行处理与合并:

    // express为例
    const multiparty = require('multiparty');
    const path = require('path');
    const fse = require('fs-extra');

    const form = new multiparty.Form();
    form.parse(req, async (err, fields, files) => {
    if (err) {
    return res.send({
    code: 1001,
    msg: '切片上传失败',
    });
    }
    // 获取切片文件
    const chunk = files.chunk[0];
    // 创建临时目录
    const chunkDir = path.resolve(uploadDir, `${fileName}-chunks`);
    await fse.ensureDir(chunkDir);

    // 把切片移动到临时目录
    await fse.move(chunk.path, `${chunkDir}/${chunk.originalFilename}`);
    // 合并切片文件
    await mergeFileChunk(filePath, chunkDir, size);
    res.send({
    code: 0,
    msg: '切片上传成功',
    });
    });
  2. 后端返回给前端一个可访问的文件 url,格式如https://www.xxx.com/backend_folder/xxx.mp4

视频切片

  1. 后端将视频文件xxx.mp4进行切片处理,生成m3u8索引文件和多个ts切片文件。
  2. m3u8ts文件存放在backend_folder下的某个目录,如static
  3. 此时m3u8文件可通过类似https://www.xxx.com/backend_folder/static/xxx.m3u8 的 url 访问。

前端播放

  1. 前端拿到m3u8的 url 后,传给视频播放器,如xgplayer:
    const player = new Player({
    id: 'video',
    url: 'https://www.xxx.com/backend_folder/static/xxx.m3u8',
    });
  2. 播放器通过m3u8索引文件逐个加载ts切片进行播放,实现分段加载。

大文件切片的意义

视频文件通常较大,如果整个文件一次性上传,很容易出现超时失败的情况。而且上传是无状态的,只有文件全部上传完才能知道是否上传成功。

切片上传可以把大文件分成多个小的文件块,每一块单独上传。这样即使某个切片上传失败,也只需重新上传这一个切片,而不是整个文件重传。同时还可以并发上传多个切片,提高上传速度。

切片上传为大文件的上传提供了可恢复、可断点续传的能力,是上传大文件的最佳实践之一。