以前给网页展示的rtsp流,使用crtmpserver做了稍加改动后转推过去的,但随着flash的淘汰,videojs这个项目组也打算在这次升级中淘汰掉,改用flvjs。
问题就是flvjs不支持rtmp,而要在crtmpserver上添加新的转流代码,一是实力不够,二是时间不够,于是选了一个成熟的http-flv框架,稍加修改。
大概流程就会是,网页要看一个rtsp的流视频,按着约定构造一个http://serverIp:serverport/live/rtsp的base64编码.flv,
例如:http://127.0.0.1:8000/live/cnRzcDovL2FkbWluOmFkbWluMTIzQDEwLjIuMy4xMDE=.flv
这样,在转推流的server收到这个请求,会截取到这个base64,解码后调用ffmpeg做一个推流,推个rtmp到流回来。
应为nodejs可以注册事件,而且可以在链接connect和disconnect的时候对ffmpeg的调用经行管理。
1 const { globalAgent } = require('http'); 2 const NodeMediaServer = require('node-media-server'); 3 const numCPUs = require('os').cpus().length; 4 var HashMap = require('hashmap').HashMap; 5 6 const config = { 7 rtmp: { 8 port: 1935, 9 chunk_size: 60000, 10 gop_cache: true, 11 ping: 60, 12 ping_timeout: 30 13 }, 14 15 http: { 16 port: 8000, 17 allow_origin: '*' 18 }, 19 cluster: { 20 num: numCPUs 21 } 22 } 23 24 var nms = new NodeMediaServer(config) 25 nms.run(); 26 27 var pmap = new HashMap(); 28 var cmap = new HashMap(); 29 const exec = require('child_process').execFile; 30 31 function strsub( str ) { 32 var list = str.split( "/" ); 33 return list[2] 34 } 35 36 nms.on('preConnect', (id, args)=>{ 37 console.log('[NodeEvent on preConnect]', `id=${id} args=${JSON.stringify(args)}`); 38 jobj = JSON.stringify(args); 39 console.log(args['streamPath']); 40 if ( args['streamPath'] != undefined ) { 41 var base64 = strsub( args['streamPath']) ; 42 var tmp = new Buffer( base64, 'base64' ); 43 var rtsp = tmp.toString(); 44 console.log( base64, rtsp ); 45 if ( cmap.has( base64 ) ) { 46 num = cmap.get( base64 ); 47 num = num + 1; 48 cmap.set( base64, num ); 49 } else { 50 pro = exec( "ffmpeg.exe", ["-rtsp_transport", "tcp", "-i", rtsp, "-vcodec", "copy", "-acodec", "aac", "-f", "flv", "rtmp://127.0.0.1" + args['streamPath'] ],function(err,stdout,stderr){ 51 if(err){ 52 console.error(err); 53 } 54 }); 55 cmap.set( base64, 1 ); 56 pmap.set( base64, pro.pid ); 57 } 58 } 59 }); 60 61 nms.on('doneConnect', (id, args) => { 62 console.log('[NodeEvent on doneConnect]', `id=${id} args=${JSON.stringify(args)}`); 63 if ( args['streamPath'] != undefined ) { 64 var base64 = strsub( args['streamPath']) ; 65 console.log( base64 ); 66 if ( cmap.has( base64 ) ) { 67 num = cmap.get( base64 ); 68 pro = pmap.get( base64 ); 69 num -= 1; 70 cmap.set( base64, num ); 71 console.log( num, pro ); 72 if ( num == 0 ) { 73 exec( "taskkill", [ "/F", "/PID", pro ] ); 74 cmap.remove( base64 ); 75 pmap.remove( base64 ); 76 } 77 } 78 } 79 });