整体架构方案
- 上传模块
- 使用
http
模块的IncomingMessage
作为上传视频流的入口。当客户端发起视频上传请求时,IncomingMessage
会接收视频数据。
- 可以通过
formidable
等库来解析包含视频文件的表单数据,将视频数据以可读流(Readable Stream
)的形式获取。例如:
const http = require('http');
const formidable = require('formidable');
const server = http.createServer((req, res) => {
const form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
const videoReadableStream = fs.createReadStream(files.video.path);
// 后续处理视频可读流
});
});
server.listen(3000);
- 转码模块
- 接收来自上传模块的可读流,使用
fluent - ffprobe
获取视频格式信息。例如:
const ffmpeg = require('fluent - ffmpeg');
const probe = require('fluent - ffprobe');
const inputStream = videoReadableStream;
probe(inputStream, (err, metadata) => {
const format = metadata.format.format_name;
// 根据格式设置转码参数
});
- 根据获取的视频格式,设置合适的转码参数,使用`fluent - ffmpeg`进行转码。转码过程中,输入是来自上传模块的可读流,输出是可写流(`Writable Stream`)。例如:
const outputStream = fs.createWriteStream('transcoded_video.mp4');
ffmpeg(inputStream)
.output(outputStream)
.on('end', () => {
console.log('Transcoding completed');
})
.run();
- 推流模块
- 接收转码后的可写流,使用
rtmp - server
等库将转码后的视频实时推流。例如,使用node - rtmp - server
:
const RtmpServer = require('node - rtmp - server');
const rtmpServer = new RtmpServer();
const transcodedStream = outputStream;
rtmpServer.on('connection', (connection) => {
connection.publish('streamName', transcodedStream);
});
rtmpServer.listen(1935);
各模块间通过Stream的数据交互
- 上传模块 -> 转码模块:上传模块通过
fs.createReadStream
等方式创建一个可读流,将视频数据源源不断地提供给转码模块。转码模块将这个可读流作为fluent - ffmpeg
的输入流。
- 转码模块 -> 推流模块:转码模块在转码完成后,将转码后的视频数据以可写流的形式提供给推流模块。推流模块使用这个可写流进行实时推流。
应对不同视频格式带来的兼容性问题
- 格式探测:在转码模块中,使用
fluent - ffprobe
等工具探测上传视频的格式。通过分析格式信息,确定转码所需的参数,如编解码器、分辨率、帧率等。
- 通用转码设置:为常见的视频格式设置通用的转码参数,以确保转码后的视频能够在主流的播放器和平台上播放。例如,将不同格式转码为
H.264
编码、MP4
容器格式,这是一种兼容性较高的组合。
- 错误处理与日志记录:在转码过程中,捕获因格式不兼容导致的错误,如编解码器不支持等。记录详细的日志信息,以便快速定位和解决问题。同时,可以向客户端返回友好的错误提示,告知用户视频格式不被支持。