我正在学习node.js与socket.io和c#之间的流媒体。
我有使用ffmpeg成功记录屏幕的代码,将其重定向到StandardOutput.BaseStream并将其存储到Memorybuffer中,当我在我的应用程序中单击停止时,它将内存流作为字节数组发送到存储的node.js服务器该文件,以便客户端可以播放它。这工作得很好,这是我的设置:
C#
bool ffWorkerIsWorking = false;
private void btnFFMpeg_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker ffWorker = new BackgroundWorker();
ffWorker.WorkerSupportsCancellation = true;
ffWorker.DoWork += ((ffWorkerObj,ffWorkerEventArgs) =>
{
ffWorkerIsWorking = true;
using (var FFProcess = new Process())
{
var processStartInfo = new ProcessStartInfo
{
FileName = "ffmpeg.exe",
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = false,
Arguments = " -loglevel panic -hide_banner -y -f gdigrab -draw_mouse 1 -i desktop -threads 2 -deadline realtime -f webm -"
};
FFProcess.StartInfo = processStartInfo;
FFProcess.Start();
byte[] buffer = new byte[32768];
using (MemoryStream ms = new MemoryStream())
{
while (!FFProcess.HasExited)
{
int read = FFProcess.StandardOutput.BaseStream.Read(buffer, 0, buffer.Length);
if (read <= 0)
break;
ms.Write(buffer, 0, read);
Console.WriteLine(ms.Length);
if (!ffWorkerIsWorking)
{
clientSocket.Emit("video", ms.ToArray());
ffWorker.CancelAsync();
break;
}
}
}
}
});
ffWorker.RunWorkerAsync();
}
JS(服务器)
socket.on('video', function(data) {
fs.appendFile('public/fooTest.webm', data, function (err) {
if (err) throw err;
console.log('File uploaded');
});
});
现在我需要更改此代码,因此它不应发送整个文件,而应发送字节数组块而不是整个视频,然后节点将首先创建一个文件然后附加那些字节数组块,因为它们是接收。好听的声音很容易,但显然不是。
我需要以某种方式指示代码使用偏移量,然后只使用该偏移量后的字节,然后更新偏移量。
在服务器端,我认为最好的方法是创建一个文件,并在接收到该文件时将字节数组附加到该文件中。
在服务器端,我会做这样的事情:
JS(服务器)
var buffer = new Buffer(32768);
var isBuffering = false;
socket.on('video', function(data) {
//concatenate the buffer with the incoming data and broadcast.emit to clients
});
我如何设置要发送的字节的偏移量并更新该偏移量,以及如何处理将数据连接到初始化缓冲区的方式?
我曾尝试编写一些只能从偏移读取到最后的代码,虽然在节点中添加的视频只是黑色,但它似乎仍在工作:
C#
while (!FFProcess.HasExited)
{
int read = FFProcess.StandardOutput.BaseStream.Read(buffer, 0, buffer.Length);
if (read <= 0)
break;
int offset = (read - buffer.Length > 0 ? read - buffer.Length : 0);
ms.Write(buffer, offset, read);
clientSocket.Emit("videoChunk", buffer.ToArray());
if (!ffWorkerIsWorking)
{
ffWorker.CancelAsync();
break;
}
}
节点控制台输出
JS(服务器)
socket.on('videoChunk', function(data) {
if (!isBufferingDone) {
buffer = Buffer.concat([buffer, data]);
console.log(data.length);
}
});
socket.on('cancelVideo', function() {
isBufferingDone = true;
setTimeout(function() {
fs.writeFile("public/test.webm", buffer, function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
buffer = new Buffer(32768);
});
}, 1000);
});
JS(客户端)
socket.on('video', function(filePath) {
console.log('path: ' + filePath);
$('#videoSource').attr('src',filePath);
$('#video').play();
});
谢谢!