owned this note
owned this note
Published
Linked with GitHub
https://www.educba.com/websocket-vs-socket-io/
https://support.theoplayer.com/hc/en-us/articles/206932789-Cross-Origin-Resource-Sharing
socket 通信
https://yogurt.iteye.com/blog/1968272
https://sites.google.com/site/ucanlab/Home/chimain/opensource/scocket-programming-with-dev-c
https://studygolang.com/articles/4664
轉換流解決方案
https://stackoverflow.com/questions/19658216/how-can-we-transcode-live-rtmp-stream-to-live-hls-stream-using-ffmpeg
https://www.youtube.com/watch?v=W9QYOwSmc5c
https://412887952-qq-com.iteye.com/blog/1620334
```
Console.WriteLine("Starting:Creating Socket object");
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(new IPEndPoint(IPAddress.Any, 2112));
listener.Listen(10);
while (true)
{
Console.WriteLine("Waiting for connection on port 2112");
Socket socket = listener.Accept();
string receivedValue = string.Empty;
while (true)
{
byte[] receivedBytes = new byte[1024];
int numBytes = socket.Receive(receivedBytes);
Console.WriteLine("Receiving.");
receivedValue += Encoding.ASCII.GetString(receivedBytes, 0, numBytes);
if (receivedValue.IndexOf("[FINAL]") > -1)
{
break;
}
}
Console.WriteLine("Received value:{0}", receivedValue);
string replyValue = "Message successfully received.";
byte[] replyMessage = Encoding.ASCII.GetBytes(replyValue);
socket.Send(replyMessage);
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
```C:\Users\Administrator>ffmpeg -re -i rtmp://localhost/live/myCamera -s 640x480 -
vcodec copy -tune zerolatency -filter_complex aresample=44100 -bufsize 1000
-c:a aac -b:a:0 128k -f flv rtmp://localhost/livepkgr/livestream?adbe-live-event
=liveevent
https://dotblogs.com.tw/atowngit/2009/12/19/12547
https://www.one-tab.com/page/yWlxqQR9RIuT2oumjQXJtg
https://www.one-tab.com/page/vsoW7_TMQUyTyZ7TtcUrSg
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
Process process;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ProcessStartInfo pinfo = new ProcessStartInfo("c:\\ffmpeg\\bin\\ffmpeg.exe");
pinfo.Arguments = "-re -i rtmp://localhost/live/mycamera -s 640x480 -vcodec copy -tune zerolatency -filter_complex aresample=44100 -bufsize 1000 -c:a aac -b:a:0 128k -f flv rtmp://localhost/livepkgr/livestream?adbe-live-event=liveevent";
process= Process.Start("calc.exe");
process.EnableRaisingEvents = true;
process.SynchronizingObject = this;
process.Exited += new EventHandler(process_Exited);
MessageBox.Show("Main Thread ID:" + Thread.CurrentThread.ManagedThreadId.ToString());
//pinfo.UseShellExecute = false; //必须为false
//pinfo.RedirectStandardOutput = true;
//pinfo.CreateNoWindow = true;
//using (Process p = new Process())
//{
// p.EnableRaisingEvents = true;
// p.StartInfo = pinfo;
// p.Exited += new EventHandler(P_Exited);
// p.Start();
// //p.BeginOutputReadLine();
//}
}
void process_Exited(object sender, EventArgs e)
{
while (!process.HasExited)
{
Thread.Sleep(1);
Application.DoEvents();
}
MessageBox.Show("Process Thread ID:" + Thread.CurrentThread.ManagedThreadId.ToString());
}
private void button2_Click(object sender, EventArgs e)
{
MessageBox.Show("Process Thread ID:" + process.Responding.ToString());
}
}
}
```
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Process process = new Process();
//Environment.GetEnvironmentVariable("WinDir") + "\\Notepad.exe";
// process.StartInfo.FileName = "C:\\ffmpeg\\bin\\ffmpeg.exe -re -i rtmp://localhost/live/myCamera -s 640x480 -vcodec copy -tune zerolatency - filter_complex aresample = 44100 - bufsize 1000 - c:a aac -b:a: 0 128k - f flv rtmp://localhost/livepkgr/livestream?adbe-live-event= liveevent";
ProcessStartInfo pinfo = new ProcessStartInfo("ffmpeg");
pinfo.Arguments = "-re -i rtmp://localhost/live/myCamera -s 640x480 -vcodec copy -tune zerolatency -filter_complex aresample=44100 -bufsize 1000 -c:a aac -b:a:0 128k -f flv rtmp://localhost/livepkgr/livestream?adbe-live-event=liveevent";
process.StartInfo = pinfo;
process.Start();
process.Exited += new EventHandler(process_Exited);
process.SynchronizingObject = this;
process.EnableRaisingEvents = true;
}
void process_Exited(object sender, EventArgs e)
{
MessageBox.Show("Notepad.exe 已被關閉!!!");
}
}
}
```
好參數
```
try{
cam = Camera.getCamera();
cam.setMode(1027, 768,30);
/**
* public function setKeyFrameInterval(keyFrameInterval:int):void
* The number of video frames transmitted in full (called keyframes) instead of being interpolated by the video compression algorithm.
* The default value is 15, which means that every 15th frame is a keyframe. A value of 1 means that every frame is a keyframe.
* The allowed values are 1 through 300.
*/
cam.setKeyFrameInterval(15);
/**
* public function setQuality(bandwidth:int, quality:int):void
* bandwidth:int — Specifies the maximum amount of bandwidth that the current outgoing video feed can use, in bytes per second (bps).
* To specify that the video can use as much bandwidth as needed to maintain the value of quality, pass 0 for bandwidth.
* The default value is 16384.
* quality:int — An integer that specifies the required level of picture quality, as determined by the amount of compression
* being applied to each video frame. Acceptable values range from 1 (lowest quality, maximum compression) to 100
* (highest quality, no compression). To specify that picture quality can vary as needed to avoid exceeding bandwidth,
* pass 0 for quality.
*/
cam.setQuality(0,100);
/**
* public function setProfileLevel(profile:String, level:String):void
* Set profile and level for video encoding.
* Possible values for profile are H264Profile.BASELINE and H264Profile.MAIN. Default value is H264Profile.BASELINE.
* Other values are ignored and results in an error.
* Supported levels are 1, 1b, 1.1, 1.2, 1.3, 2, 2.1, 2.2, 3, 3.1, 3.2, 4, 4.1, 4.2, 5, and 5.1.
* Level may be increased if required by resolution and frame rate.
*/
//var h264setting:H264VideoStreamSettings = new H264VideoStreamSettings();
//h264setting.setProfileLevel(H264Profile.BASELINE, H264Level.LEVEL_3_1);
//Mic
mic = Microphone.getMicrophone();
/*
* The encoded speech quality when using the Speex codec. Possible values are from 0 to 10. The default value is 6.
* Higher numbers represent higher quality but require more bandwidth, as shown in the following table.
* The bit rate values that are listed represent net bit rates and do not include packetization overhead.
* ------------------------------------------
* Quality value | Required bit rate (kbps)
*-------------------------------------------
* 0 | 3.95
* 1 | 5.75
* 2 | 7.75
* 3 | 9.80
* 4 | 12.8
* 5 | 16.8
* 6 | 20.6
* 7 | 23.8
* 8 | 27.8
* 9 | 34.2
* 10 | 42.2
*-------------------------------------------
*/
mic.encodeQuality = 9;
/* The rate at which the microphone is capturing sound, in kHz. Acceptable values are 5, 8, 11, 22, and 44. The default value is 8 kHz
* if your sound capture device supports this value. Otherwise, the default value is the next available capture level above 8 kHz that
* your sound capture device supports, usually 11 kHz.
*
*/
mic.rate = 44;
ns = new NetStream(nc);
var h264Settings:H264VideoStreamSettings=new H264VideoStreamSettings();
h264Settings.setProfileLevel(H264Profile.MAIN, H264Level.LEVEL_5_1);
h264Settings.setMode(1027, 768, 30);
h264Settings.setQuality(0, 100);
//H.264 Setting
ns.videoStreamSettings =h264Settings;
ns.attachCamera(cam);
ns.attachAudio(mic);
ns.publish(publish_name, play_type);
```
pinfo.Arguments = "-re -i rtmp://localhost/live/myCamera -r 60 -vcodec copy -tune zerolatency -filter_complex aresample=44100" +
" -bufsize 2000 -c:a aac -b:a:0 128k -f flv rtmp://localhost/livepkgr/livestream?adbe-live-event=liveevent";
c# thread 呼叫
```
using System;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static String nProcessID;
static int count = 0;
public static void process_Exited(object sender, EventArgs e)
{
Console.WriteLine(nProcessID);
//Console.WriteLine("exit");
}
public static void call_process_ffmpeg(object name)
{
string thread_name = (string)name; //unboxing
Process process = new Process();
//Environment.GetEnvironmentVariable("WinDir") + "\\Notepad.exe";
// process.StartInfo.FileName = "C:\\ffmpeg\\bin\\ffmpeg.exe -re -i rtmp://localhost/live/myCamera -s 640x480 -vcodec copy -tune zerolatency - filter_complex aresample = 44100 - bufsize 1000 - c:a aac -b:a: 0 128k - f flv rtmp://localhost/livepkgr/livestream?adbe-live-event= liveevent";
ProcessStartInfo pinfo = new ProcessStartInfo("ffmpeg");
pinfo.Arguments = "-re -i rtmp://localhost/live/myCamera -r 30 -vcodec copy -tune zerolatency -filter_complex aresample=44100 -bufsize 1000 -c:a aac -b:a:0 128k -f flv rtmp://localhost/livepkgr/livestream?adbe-live-event=liveevent";
process.StartInfo = pinfo;
process.Start();
process.Exited += new EventHandler(process_Exited);
process.EnableRaisingEvents = true;
// process.WaitForInputIdle();
nProcessID = process.SessionId.ToString();
process.WaitForExit();
Console.WriteLine(thread_name +"exit");
}
static void Main(string[] args)
{
Thread test = new Thread( new ParameterizedThreadStart(call_process_ffmpeg));
test.Start("test1");
Thread test2 = new Thread(new ParameterizedThreadStart(call_process_ffmpeg));
test2.Start("test2");
Console.ReadLine();
}
}
}
```
```
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static String nProcessID;
static int count = 0;
public static void process_Exited(object sender, EventArgs e)
{
Console.WriteLine(nProcessID);
//Console.WriteLine("exit");
}
public static void call_process_ffmpeg(object name)
{
string thread_name = (string)name; //unboxing
Process process = new Process();
//Environment.GetEnvironmentVariable("WinDir") + "\\Notepad.exe";
// process.StartInfo.FileName = "C:\\ffmpeg\\bin\\ffmpeg.exe -re -i rtmp://localhost/live/myCamera -s 640x480 -vcodec copy -tune zerolatency - filter_complex aresample = 44100 - bufsize 1000 - c:a aac -b:a: 0 128k - f flv rtmp://localhost/livepkgr/livestream?adbe-live-event= liveevent";
ProcessStartInfo pinfo = new ProcessStartInfo("ffmpeg");
pinfo.Arguments = "-re -i rtmp://localhost/live/myCamera -r 30 -vcodec copy -tune zerolatency -filter_complex aresample=44100 -bufsize 1000 -c:a aac -b:a:0 128k -f flv rtmp://localhost/livepkgr/livestream?adbe-live-event=liveevent";
process.StartInfo = pinfo;
process.Start();
process.Exited += new EventHandler(process_Exited);
process.EnableRaisingEvents = true;
// process.WaitForInputIdle();
nProcessID = process.SessionId.ToString();
process.WaitForExit();
Console.WriteLine(thread_name +"exit");
}
static void Main(string[] args)
{
List<Thread> threads = new List<Thread>();
for (int i = 0; i < 10; i++)
{
Thread tmp = new Thread(new ParameterizedThreadStart(call_process_ffmpeg));
threads.Add(tmp);
}
int count = 0;
foreach (Thread tmp in threads)
{
tmp.Start(count.ToString());
count++;
}
//for (int i = 0; i < threads.)
//Thread test = new Thread( new ParameterizedThreadStart(call_process_ffmpeg));
//test.Start("test1");
//Thread test2 = new Thread(new ParameterizedThreadStart(call_process_ffmpeg));
//test2.Start("test2");
//Console.ReadLine();
}
}
}
```
https://github.com/gwuhaolin/blog/issues/3
https://blog.csdn.net/the_victory/article/details/79666702
https://blog.csdn.net/mengzhengjie/article/details/71280007
https://d887419.wordpress.com/2017/04/23/nvidia-%E9%A1%AF%E5%8D%A1%E7%9A%84-cuvid-decoder-ffmpeg-decoder-name/
https://ithelp.ithome.com.tw/articles/10192437
\
https://13521308103.iteye.com/blog/1997136
http://yindingtsai.blogspot.com/2010/01/runtimeexec.html
https://ithelp.ithome.com.tw/articles/10203335
var express = require('express');
var app = express();
//var http = require('http').Server(app);
//var ffmpeg = require('fluent-ffmpeg');
//var stream = require('stream');
var spawn = require('child_process').spawn;
var fs = require('fs');
app.use(express.static('static'));
const server = require('https').createServer({
key: fs.readFileSync('abels-key.pem'),
cert: fs.readFileSync('abels-cert.pem')
},app);
//testing
var io = require('socket.io')(server);
spawn('ffmpeg',['-h']).on('error',function(m){
console.error("FFMpeg not found in system cli; please install ffmpeg properly or make a softlink to ./!");
process.exit(-1);
});
io.on('connection', function(socket){
socket.emit('message','Hello from mediarecorder-to-rtmp server!');
socket.emit('message','Please set rtmp destination before start streaming.');
var ffmpeg_process, feedStream=false;
socket.on('config_rtmpDestination',function(m){
if(typeof m != 'string'){
socket.emit('fatal','rtmp destination setup error.');
return;
}
var regexValidator=/^rtmp:\/\/[^\s]*$/;//TODO: should read config
if(!regexValidator.test(m)){
socket.emit('fatal','rtmp address rejected.');
return;
}
socket._rtmpDestination=m;
socket.emit('message','rtmp destination set to:'+m);
});
//socket._vcodec='libvpx';//from firefox default encoder
socket.on('config_vcodec',function(m){
if(typeof m != 'string'){
socket.emit('fatal','input codec setup error.');
return;
}
if(!/^[0-9a-z]{2,}$/.test(m)){
socket.emit('fatal','input codec contains illegal character?.');
return;
}//for safety
socket._vcodec=m;
});
socket.on('start',function(m){
if(ffmpeg_process || feedStream){
socket.emit('fatal','stream already started.');
return;
}
if(!socket._rtmpDestination){
socket.emit('fatal','no destination given.');
return;
}
var ops=[
'-i','-',
'-r','60',
'-vcodec', 'libx264',
'-preset','ultrafast',
'-b:v', '400k',
'-s', '480x360',
'-tune' ,'zerolatency',
//'-preset', 'ultrafast',
//'-an', //TODO: give up audio for now...
//'-async', '1',
'-filter_complex', 'aresample=44100', //necessary for trunked streaming?
'-strict', 'experimental',
//'-strict', 'experimental', '-c:a', 'aac', '-b:a', '128k',
//'-bufsize', '1000',
"-fflags",'nobuffer',
'-analyzeduration','0',
'-c:a', 'aac' ,
'-b:a:0', '64k',
'-benchmark',
'-f', 'flv', socket._rtmpDestination
];
console.log(socket._rtmpDestination);
ffmpeg_process=spawn('ffmpeg', ops);
feedStream=function(data){
ffmpeg_process.stdin.write(data);
//write exception cannot be caught here.
}
ffmpeg_process.stderr.on('data',function(d){
socket.emit('ffmpeg_stderr',''+d);
});
ffmpeg_process.on('error',function(e){
console.log('child process error'+e);
socket.emit('fatal','ffmpeg error!'+e);
feedStream=false;
socket.disconnect();
});
ffmpeg_process.on('exit',function(e){
console.log('child process exit'+e);
socket.emit('fatal','ffmpeg exit!'+e);
socket.disconnect();
});
});
socket.on('binarystream',function(m){
if(!feedStream){
socket.emit('fatal','rtmp not set yet.');
return;
}
feedStream(m);
});
socket.on('disconnect', function () {
feedStream=false;
if(ffmpeg_process)
try{
ffmpeg_process.stdin.end();
ffmpeg_process.kill('SIGINT');
}catch(e){console.warn('killing ffmoeg process attempt failed...');}
});
socket.on('error',function(e){
console.log('socket.io error:'+e);
});
});
io.on('error',function(e){
console.log('socket.io error:'+e);
});
//http.listen(8888, function(){
// console.log('http and websocket listening on *:8888');
//});
server.listen(443, function(){
console.log('https and websocket listening on *:443');
});
process.on('uncaughtException', function(err) {
// handle the error safely
console.log(err)
// Note: after client disconnect, the subprocess will cause an Error EPIPE, which can only be caught this way.
})
var ops=[
'-i','-',
'-r','60',
'-vcodec', 'libx264',
'-preset','ultrafast',
'-b:v', '400k',
'-s', '480x360',
'-tune' ,'zerolatency',
//'-preset', 'ultrafast',
//'-an', //TODO: give up audio for now...
//'-async', '1',
'-filter_complex', 'aresample=44100', //necessary for trunked streaming?
'-strict', 'experimental',
//'-strict', 'experimental', '-c:a', 'aac', '-b:a', '128k',
//'-bufsize', '1000',
"-fflags",'nobuffer',
'-analyzeduration','0',
'-c:a', 'aac' ,
'-b:a:0', '64k',
'-benchmark',
'-f', 'flv', socket._rtmpDestination
];
# iiiiiiiiii
<!doctype>
<html>
<head>
<title>MediaRecorder to RTMP Demo</title>
<script src="/socket.io/socket.io.js"></script>
</head>
<body style="max-width:800px;height:100%;margin:auto;">
<h1>
MediaRecorder to RTMP Demo
</h1>
<label for="option_width" >Size:</label>
<input type="text" id="option_width" value="480"/> ×
<input type="text" id="option_height" value="360"/>
<br>
<label for="option_url" >RTMP Destination:</label>
<input type="text" id="option_url" value="rtmp://localhost/live"/>
<br>
<button id="button_start">Start streaming</button>
<hr/>
<div>
<p id="output_message"></p>
<video id="output_video" autoplay=true></video>
</div>
<hr/>
<textarea readonly="true" id="output_console" cols=91 rows=5>
</textarea>
<script>
function fail(str){alert(str+"\nPlease download the latest version of Firefox!");location.replace('http://mozilla.org/firefox');}
var output_console=document.getElementById('output_console'),
output_message=document.getElementById('output_message'),
output_video=document.getElementById('output_video'),
option_url=document.getElementById('option_url'),
option_width=document.getElementById('option_width'),
option_height=document.getElementById('option_height'),
button_start=document.getElementById('button_start'),
height=option_height.value,
width=option_width.value,
url=option_url.value='rtmp://'+location.host.split(':')[0]+':1935/live/test';
option_height.onchange=option_height.onkeyup=function(){height=1*this.value;}
option_width.onchange=option_width.onkeyup=function(){width=1*this.value;}
option_url.onchange=option_url.onkeyup=function(){url=this.value;}
button_start.onclick=requestMedia;
function video_show(stream){
if ("srcObject" in output_video) {
output_video.srcObject = stream;
} else {
output_video.src = window.URL.createObjectURL(stream);
}
output_video.addEventListener( "loadedmetadata", function (e) {
output_message.innerHTML="Local video source size:"+output_video.videoWidth+"x"+output_video.videoHeight;
}, false );
}
function show_output(str){
output_console.value+="\n"+str;
output_console.scrollTop = output_console.scrollHeight;
}
navigator.getUserMedia = (navigator.getUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia ||
navigator.webkitGetUserMedia);
if(!navigator.getUserMedia){fail('No getUserMedia() available.');}
if(!MediaRecorder){fail('No MediaRecorder available.');}
var mediaRecorder;
var socket = io.connect("https://localhost", {secure: true});
//({
// option 1
// ca: fs.readFileSync("https://localhost:443",'./abels-cert.pem'),
// option 2. WARNING: it leaves you vulnerable to MITM attacks!
// requestCert: false,
// rejectUnauthorized: false
//});
//var socket = io.
socket.on('message',function(m){
console.log('recv server message',m);
show_output('SERVER:'+m);
});
socket.on('fatal',function(m){
show_output('ERROR: unexpected:'+m);
alert('Error:'+m);
mediaRecorder.stop();
//should reload?
});
socket.on('ffmpeg_stderr',function(m){
show_output('FFMPEG:'+m);
});
socket.on('disconnect', function () {
show_output('ERROR: server disconnected!');
mediaRecorder.stop();
});
function requestMedia(){
var constraints = { audio: true,
video:{
width: { min: width, ideal: width, max: width },
height: { min: height, ideal: height, max: height },
}
};
navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
video_show(stream);//only show locally, not remotely
socket.emit('config_rtmpDestination',url);
socket.emit('start','start');
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start(0);
mediaRecorder.onstop = function(e) {
stream.stop();
}
mediaRecorder.ondataavailable = function(e) {
socket.emit("binarystream",e.data);
//chunks.push(e.data);
}
}).catch(function(err) {
console.log('The following error occured: ' + err);
show_output('Local getUserMedia ERROR:'+err);
});
}
</script>
</body>
</html>
https://www.jianshu.com/p/92e32d6e7190
https://www.one-tab.com/page/SL0YBc_7QW-ENq1NMjW5Yw
# ffmpeg gpu 加速
https://blog.csdn.net/qq_39575835/article/details/83826073
https://juejin.im/post/5b0f69e46fb9a009f41479b4#heading-0
https://www.bilibili.com/read/cv1570233/
http://nodejs.cn/api/child_process.html
https://segmentfault.com/a/1190000007735211
http://nodejs.cn/api/cluster.html
https://larrylu.blog/nodejs-pm2-cluster-455ffbd7671
https://ithelp.ithome.com.tw/articles/10202999