Module = {
|
onRuntimeInitialized: function() {
|
onWasmLoaded()
|
},
|
}
|
importScripts('libffmpeg.js')
|
|
var MediaName = null
|
var IsStream = true
|
var FileLen = -1
|
|
var SocketObj //WebSocket
|
var CPointer_Buffer = null
|
var CPointer_Cap = 0
|
|
function onWasmLoaded() {
|
DeliverVideo = Module.addFunction(function(Buf, BufLen, TimeStamp) {
|
var CPointer_Array = Module.HEAPU8.subarray(Buf, Buf + BufLen)
|
var message = {
|
command: 'deliver_video',
|
sample: { time_stamp: TimeStamp, buf: new Uint8Array(CPointer_Array) },
|
}
|
self.postMessage(message, [message.sample.buf.buffer])
|
}, 'viii')
|
|
DeliverAudio = Module.addFunction(function(Buf, BufLen, TimeStamp) {
|
var CPointer_Array = Module.HEAPU8.subarray(Buf, Buf + BufLen)
|
var message = {
|
command: 'deliver_audio',
|
sample: { time_stamp: TimeStamp, buf: new Uint8Array(CPointer_Array) },
|
}
|
self.postMessage(message, [message.sample.buf.buffer])
|
}, 'viii')
|
|
GetFileLength = Module.addFunction(function() {
|
if (FileLen == -1) {
|
var xhr = new XMLHttpRequest()
|
xhr.open('get', MediaName, false) //false: syn mode
|
xhr.send()
|
FileLen = xhr.getResponseHeader('Content-Length')
|
xhr.abort()
|
}
|
return FileLen
|
}, 'i')
|
|
ReadFile = Module.addFunction(function(Buf, Pos, Size) {
|
var xhr = new XMLHttpRequest()
|
xhr.open('get', MediaName, false)
|
xhr.responseType = 'arraybuffer'
|
xhr.setRequestHeader('Range', 'bytes=' + Pos + '-' + (Pos + Size - 1))
|
xhr.send()
|
Module.HEAPU8.set(new Uint8Array(xhr.response), Buf) //Uint8Array(xhr.response).length
|
xhr.abort()
|
}, 'viii')
|
|
CreateVideo = Module.addFunction(function(Duration, Width, Height) {
|
self.postMessage({
|
command: 'create_video',
|
param: { duration: Duration, width: Width, height: Height },
|
})
|
}, 'viii')
|
|
CreateAudio = Module.addFunction(function(Channel, SampleRate) {
|
self.postMessage({
|
command: 'create_audio',
|
param: { channel: Channel, sample_rate: SampleRate },
|
})
|
}, 'vii')
|
|
Notify = Module.addFunction(function(Type, Value) {
|
//type 1:播放失败 2:文件播放到末尾
|
//console.log(Type+" "+Value);
|
if (Type == 1) self.postMessage({ command: 'play_failed' })
|
else if (Type == 2) self.postMessage({ command: 'play_end' })
|
}, 'vii')
|
|
Module._Initialize(
|
DeliverVideo,
|
DeliverAudio,
|
GetFileLength,
|
ReadFile,
|
CreateVideo,
|
CreateAudio,
|
Notify
|
)
|
|
self.postMessage({ command: 'initialized' })
|
}
|
|
function OnTimer() {
|
Module._Turbo0(null, 0)
|
}
|
|
function requestWebsocket(url, msg, cb_message) {
|
SocketObj = new WebSocket(url)
|
SocketObj.binaryType = 'arraybuffer'
|
SocketObj.onopen = function(evt) {
|
SocketObj.send(msg)
|
}
|
SocketObj.onerror = function(evt) {
|
console.log('Ws connect error ' + evt.data)
|
}
|
SocketObj.onmessage = cb_message
|
SocketObj.onclose = function() {
|
console.log('Ws closed.')
|
}
|
}
|
|
function downloadFileByWebsocket(ws, payload) {
|
this.requestWebsocket(ws, payload, function(evt) {
|
if (evt.data.byteLength > CPointer_Cap) {
|
if (CPointer_Buffer != null) Module._free(CPointer_Buffer)
|
CPointer_Cap = evt.data.byteLength
|
CPointer_Buffer = Module._malloc(CPointer_Cap)
|
}
|
|
var typedArray = new Uint8Array(evt.data)
|
Module.HEAPU8.set(typedArray, CPointer_Buffer)
|
//console.log("websocket data: "+typedArray.length);
|
Module._Turbo0(CPointer_Buffer, typedArray.length)
|
})
|
}
|
|
self.onmessage = function(evt) {
|
switch (evt.data.command) {
|
case 'play': {
|
MediaName = evt.data.media_name
|
IsStream = evt.data.other
|
if (IsStream) {
|
downloadFileByWebsocket(MediaName, evt.data.payload)
|
}
|
|
Module._Play(null, !IsStream)
|
TimerID = setInterval(OnTimer, 5) //此值越小,渲染精度越高,且可增强'双线程缓冲平滑机制'可靠性
|
break
|
}
|
case 'pause': {
|
Module._Pause()
|
clearInterval(TimerID)
|
break
|
}
|
case 'resume': {
|
Module._Resume()
|
TimerID = setInterval(OnTimer, 5)
|
break
|
}
|
case 'stop': {
|
Module._Stop()
|
clearInterval(TimerID)
|
if (IsStream) {
|
SocketObj.close()
|
if (CPointer_Buffer != null) {
|
Module._free(CPointer_Buffer)
|
CPointer_Buffer = null
|
CPointer_Cap = 0
|
}
|
}
|
close() //exit worker
|
break
|
}
|
case 'seek': {
|
Module._Seek(evt.data.pos)
|
break
|
}
|
default:
|
return
|
}
|
}
|