Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
P
ParaEncode
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ParaEncode
Commits
0e0f0d0d
Commit
0e0f0d0d
authored
May 01, 2022
by
NzSN
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Test Implement H264WWGroup.
parent
55815cd7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
207 additions
and
82 deletions
+207
-82
muxWW.js
resources/workers/muxWW.js
+1
-0
WW.js
src/WW.js
+19
-5
WWOpts.js
src/WWOpts.js
+0
-6
encGroup.js
src/encGroup.js
+101
-31
paraEncode.js
src/paraEncode.js
+44
-27
utils.js
src/utils.js
+21
-0
paraEncodeSpec.spec.js
tests/paraEncodeSpec.spec.js
+21
-13
No files found.
resources/workers/muxWW.js
View file @
0e0f0d0d
...
@@ -67,6 +67,7 @@ async function init(msg) {
...
@@ -67,6 +67,7 @@ async function init(msg) {
/* Init Muxer */
/* Init Muxer */
muxer
.
_muxInit
(
numOfEncs
);
muxer
.
_muxInit
(
numOfEncs
);
postMessage
(
makeMsg
(
MESSAGE_TYPE
.
INIT
,
{}));
}
}
async
function
destroy
()
{
async
function
destroy
()
{
...
...
src/WW.js
View file @
0e0f0d0d
...
@@ -2,11 +2,18 @@
...
@@ -2,11 +2,18 @@
import
{
Observable
,
filter
}
from
'./rxjs'
;
import
{
Observable
,
filter
}
from
'./rxjs'
;
export
class
WWInitError
extends
Error
{
constructor
(
WWID
)
{
super
(
"Web worker
\
'"
+
WWID
+
"
\
' fail to initialize"
);
}
}
export
class
WW
extends
Observable
{
export
class
WW
extends
Observable
{
#
ident
=
undefined
;
#
ident
=
undefined
;
#
init
=
false
;
#
inited
=
false
;
#
bridged
=
false
;
#
healthy
=
true
;
#
healthy
=
true
;
#
ww
=
undefined
;
#
ww
=
undefined
;
#
connected
=
{};
#
connected
=
{};
...
@@ -21,9 +28,11 @@ export class WW extends Observable {
...
@@ -21,9 +28,11 @@ export class WW extends Observable {
this
.
#
ww
=
new
Worker
(
path
);
this
.
#
ww
=
new
Worker
(
path
);
}
}
async
start
(
initWorks
)
{
async
start
(
initWork
)
{
this
.
#
init
=
await
initWorks
(
this
);
this
.
#
inited
=
await
initWork
(
this
);
return
this
.
#
init
;
if
(
this
.
#
inited
==
false
)
throw
new
WWInitError
(
this
.
#
ident
);
return
this
.
#
inited
;
}
}
ident
()
{
ident
()
{
...
@@ -31,7 +40,7 @@ export class WW extends Observable {
...
@@ -31,7 +40,7 @@ export class WW extends Observable {
}
}
isReady
()
{
isReady
()
{
return
this
.
#
init
;
return
this
.
#
init
ed
;
}
}
postMessage
(
msg
)
{
postMessage
(
msg
)
{
...
@@ -76,4 +85,9 @@ export class WW extends Observable {
...
@@ -76,4 +85,9 @@ export class WW extends Observable {
return
this
.
#
ww
.
terminate
();
return
this
.
#
ww
.
terminate
();
}
}
monitor
()
{
this
.
subscribe
(
msg
=>
{
});
}
}
}
src/WWOpts.js
deleted
100644 → 0
View file @
55815cd7
export
const
COMMANDS
=
Object
.
freeze
({
INIT
:
0
,
INIT_DONE
:
1
,
INIT_FAIL
:
2
,
});
src/encGroup.js
View file @
0e0f0d0d
import
{
assert
,
sleep
}
from
'./utils.js'
;
import
{
assert
,
waitCond
}
from
'./utils.js'
;
import
{
WWGroup
}
from
'./WWGroup.js'
;
import
{
WWGroup
}
from
'./WWGroup.js'
;
import
{
WW
}
from
'./WW.js'
;
import
{
WW
,
WWInitError
}
from
'./WW.js'
;
import
{
Channel
}
from
'./channel.js'
;
import
{
Channel
}
from
'./channel.js'
;
import
{
MESSAGE_TYPE
,
makeMsg
,
isDataMsg
,
makeInitMsg
}
from
'./encGrooupMsg.js'
;
import
{
MESSAGE_TYPE
,
makeMsg
,
isDataMsg
,
makeInitMsg
,
typeOfMsg
}
from
'./encGrooupMsg.js'
;
async
function
muxInit
(
chnls
,
ww
)
{
export
class
H264EncWWGroupInitError
extends
Error
{
let
channel
=
new
Channel
(
Math
.
pow
(
2
,
20
));
constructor
(
gid
)
{
ww
.
postMessage
(
super
(
"H264EncWWGroup
\
'"
+
gid
+
"
\
' fail to initialize"
);
makeInitMsg
(
channel
.
getShMem
(),
Math
.
pow
(
2
,
20
)));
}
chnls
[
ww
.
ident
()]
=
channel
;
return
true
;
}
async
function
encInit
(
chnls
,
ww
)
{
return
await
muxInit
(
chnls
,
ww
);
}
async
function
encMuxBridge
(
bridge
,
enc
,
mux
)
{
let
channel
=
new
Channel
(
Math
.
pow
(
2
,
20
));
enc
.
postMessage
(
makeMsg
(
MESSAGE_TYPE
.
CONNECT_PREPARE
,
channel
.
getShMem
()));
mux
.
postMessage
(
makeMsg
(
MESSAGE_TYPE
.
CONNECT_PREPARE
,
channel
.
getShMem
()));
bridge
[
enc
.
ident
()]
=
channel
;
}
}
...
@@ -40,6 +24,8 @@ export class H264EncWWGroup extends WWGroup {
...
@@ -40,6 +24,8 @@ export class H264EncWWGroup extends WWGroup {
#
channels
=
{};
#
channels
=
{};
#
bridges
=
{};
#
bridges
=
{};
#
name
=
undefined
;
/* Options */
/* Options */
/* Number of frames WWGroup can handle at a time */
/* Number of frames WWGroup can handle at a time */
...
@@ -58,6 +44,8 @@ export class H264EncWWGroup extends WWGroup {
...
@@ -58,6 +44,8 @@ export class H264EncWWGroup extends WWGroup {
assert
(
typeof
(
name
)
==
"string"
,
"INVALID ARGUMENT"
);
assert
(
typeof
(
name
)
==
"string"
,
"INVALID ARGUMENT"
);
this
.
#
name
=
name
;
// Setting options
// Setting options
if
(
options
!=
undefined
)
{
if
(
options
!=
undefined
)
{
...
@@ -100,15 +88,25 @@ export class H264EncWWGroup extends WWGroup {
...
@@ -100,15 +88,25 @@ export class H264EncWWGroup extends WWGroup {
}
}
async
start
()
{
async
start
()
{
// Start Muxer
try
{
await
this
.
#
muxWorker
.
start
(
async
ww
=>
{
// Start Muxer
return
await
muxInit
(
this
.
#
channels
,
ww
);
await
this
.
#
muxWorker
.
start
(
async
ww
=>
{
});
return
await
initStrategies
(
muxInit
,
INIT_FLAGS
.
NONE
,
ww
,
// muxInit parameters
for
(
let
i
=
0
;
i
<
this
.
#
numOfEncWorker
;
++
i
)
{
this
.
#
channels
,
ww
)
await
this
.
#
encWorkers
[
i
].
start
(
async
ww
=>
{
return
await
encInit
(
this
.
#
channels
,
ww
);
});
});
for
(
let
i
=
0
;
i
<
this
.
#
numOfEncWorker
;
++
i
)
{
await
this
.
#
encWorkers
[
i
].
start
(
async
ww
=>
{
return
await
initStrategies
(
encInit
,
INIT_FLAGS
.
NONE
,
ww
,
// encInit parameters
this
.
#
channels
,
ww
);
});
}
}
catch
(
e
)
{
if
(
e
instanceof
WWInitError
)
{
throw
new
H264EncWWGroupInitError
(
this
.
#
name
);
}
}
}
// Connect Encoders to the Muxer
// Connect Encoders to the Muxer
...
@@ -130,3 +128,75 @@ export class H264EncWWGroup extends WWGroup {
...
@@ -130,3 +128,75 @@ export class H264EncWWGroup extends WWGroup {
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// Misc //
///////////////////////////////////////////////////////////////////////////////
const
INIT_FLAGS
=
Object
.
freeze
({
NONE
:
0x00
,
ASYNCHRONOUS
:
0x01
,
});
async
function
initStrategies
(
initproc
,
flags
,
ww
,
...
args
)
{
let
f
=
async
()
=>
await
initproc
(...
args
);
// Asynchronous
if
(
flags
&
INIT_FLAGS
.
ASYNCHRONOUS
)
{
f
=
f
;
}
else
{
// Do Synchronous Initialization
f
=
syncInitStrategy
(
f
,
ww
);
}
// Do initialization
let
ret
=
await
f
();
return
ret
;
}
function
syncInitStrategy
(
init
,
ww
)
{
let
inited
=
undefined
;
let
strategy
=
async
()
=>
{
let
sub
=
ww
.
subscribe
(
msg
=>
{
inited
=
typeOfMsg
(
msg
)
==
MESSAGE_TYPE
.
INIT
;
sub
.
unsubscribe
();
});
if
(
await
init
()
===
false
)
return
false
;
// Waiting 1 Second for Encoder/Muxer
let
ret
=
await
waitCond
(()
=>
inited
===
true
,
1000
);
return
ret
;
};
return
strategy
;
}
async
function
muxInit
(
chnls
,
ww
)
{
let
channel
=
new
Channel
(
Math
.
pow
(
2
,
20
));
ww
.
postMessage
(
makeInitMsg
(
channel
.
getShMem
(),
Math
.
pow
(
2
,
20
)));
chnls
[
ww
.
ident
()]
=
channel
;
return
true
;
}
async
function
encInit
(
chnls
,
ww
)
{
return
await
muxInit
(
chnls
,
ww
);
}
async
function
encMuxBridge
(
bridge
,
enc
,
mux
)
{
let
channel
=
new
Channel
(
Math
.
pow
(
2
,
20
));
enc
.
postMessage
(
makeMsg
(
MESSAGE_TYPE
.
CONNECT_PREPARE
,
channel
.
getShMem
()));
mux
.
postMessage
(
makeMsg
(
MESSAGE_TYPE
.
CONNECT_PREPARE
,
channel
.
getShMem
()));
bridge
[
enc
.
ident
()]
=
channel
;
}
src/paraEncode.js
View file @
0e0f0d0d
import
{
assert
,
NEED_TO_IMPLEMENT
}
from
'./utils.js'
;
import
{
assert
,
NEED_TO_IMPLEMENT
,
isInObj
}
from
'./utils.js'
;
import
{
ENC_GRPS
}
from
'./WWGroupList.js'
;
export
let
SUPPORT_CODECS
=
{
"h264"
:
0
};
export
const
ENCODE_MODE
=
Object
.
freeze
({
export
const
ENCODE_MODE
=
Object
.
freeze
({
URGENT
:
Symbol
(
"URGENT"
)
,
URGENT
:
0
,
SAVE_MEMORY
:
Symbol
(
"SAVEMEM"
)
,
SAVE_MEMORY
:
1
,
});
});
/* ParaEncoder use number of WebWorker specified by
/* ParaEncoder use number of WebWorker specified by
* caller to encode RGB pictures into a video */
* caller to encode RGB pictures into a video */
export
class
ParaEncoder
{
export
class
ParaEncoder
{
#
numOfWW
=
0
;
#
codec
=
undefined
;
#
mode
=
undefined
#
grp
=
null
;
constructor
(
numOfWW
,
codec
,
mode
)
{
constructor
(
numOfWW
,
codec
,
mode
)
{
assert
(
typeof
(
numOfWW
)
==
'number'
,
if
(
typeof
(
numOfWW
)
!=
'number'
||
"typeof(n umOfTR) == 'number' failed"
);
!
(
codec
in
ENC_GRPS
)
||
assert
(
typeof
(
codec
)
==
'string'
,
!
isInObj
(
ENCODE_MODE
,
mode
))
{
"typeof(codec) == 'number' failed"
);
for
(
let
encodeMode
in
ENCODE_MODE
)
{
throw
new
TypeError
(
assert
(
mode
!=
encodeMode
,
"INVALID ENCODE MODE
"
);
"Mismatch types parameter"
,
"paraEncode.js
"
);
}
}
this
.
numOfWW
=
numOfWW
;
this
.
codec
=
codec
;
this
.
#
numOfWW
=
numOfWW
;
this
.
mode
=
mode
;
this
.
#
codec
=
codec
;
this
.
#
mode
=
mode
;
}
async
init
()
{
this
.
#
grp
=
new
ENC_GRPS
[
codec
](
"ENCs"
,
{});
await
this
.
#
grp
.
start
();
}
numOfWW
()
{
return
this
.
#
numOfWW
;
}
codec
()
{
return
this
.
#
codec
;
}
mode
()
{
return
this
.
#
mode
;
}
}
/* Encode pixels into a video frame, pixels can be generated from
/* Encode pixels into a video frame, pixels can be generated from
* WebGLRenderingContext.readPixels()
* WebGLRenderingContext.readPixels()
* details: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/readPixels
* details: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/readPixels
*
*
* Pixels should be passed to worker thread */
* pixels can be null which means there are no more frames to encode,
* after that encoder will rejected any pixels.
* */
encode
(
pixels
)
{
encode
(
pixels
)
{
switch
(
this
.
mode
)
{
case
ENCODE_MODE
.
URGENT
:
return
this
.
#
encodeUrgent
(
pixels
);
case
ENCODE_MODE
.
SAVE_MEMORY
:
return
this
.
#
encodeUrgent
(
pixels
);
}
}
#
encodeUrgent
(
pixels
)
{
NEED_TO_IMPLEMENT
();
NEED_TO_IMPLEMENT
();
}
}
#
encodeSaveMem
(
pixels
)
{
/* Does all frames provide to Encoder be encoded.
*
* Note: isDone() alwasy return false before eof. */
isDone
()
{
NEED_TO_IMPLEMENT
();
NEED_TO_IMPLEMENT
();
}
}
}
}
src/utils.js
View file @
0e0f0d0d
...
@@ -16,3 +16,24 @@ export function OVERRIDE_IS_REQUIRE(message) {
...
@@ -16,3 +16,24 @@ export function OVERRIDE_IS_REQUIRE(message) {
export
async
function
sleep
(
ms
)
{
export
async
function
sleep
(
ms
)
{
await
new
Promise
(
r
=>
setTimeout
(()
=>
r
(),
ms
));
await
new
Promise
(
r
=>
setTimeout
(()
=>
r
(),
ms
));
}
}
export
function
isInObj
(
obj
,
v
)
{
const
asArray
=
Object
.
entries
(
obj
);
return
asArray
.
reduce
((
prev
,
cur
)
=>
prev
||
cur
[
1
]
==
v
,
false
);
}
export
async
function
waitCond
(
cond
,
timeout
=
500
,
intvl
=
200
)
{
let
remain
=
timeout
,
ret
=
false
;
await
new
Promise
(
resolve
=>
{
let
intvler
=
setInterval
(()
=>
{
if
((
ret
=
cond
())
||
remain
==
0
)
{
clearInterval
(
intvler
);
resolve
();
}
remain
-=
intvl
;
},
intvl
);
});
return
ret
;
}
tests/paraEncodeSpec.spec.js
View file @
0e0f0d0d
import
{
ParaEncoder
,
ENCODE_MODE
}
from
"../src/paraEncode.js"
;
import
{
ParaEncoder
,
ENCODE_MODE
}
from
"../src/paraEncode.js"
;
let
dut
=
new
ParaEncoder
(
1
,
"h264"
,
ENCODE_MODE
.
SAVE_MEMORY
);
let
paraEnc
;
beforeEach
(()
=>
{
paraEnc
=
new
ParaEncoder
(
2
,
"H264"
,
ENCODE_MODE
.
SAVE_MEMORY
);
});
describe
(
"ParaEncoder"
,
()
=>
{
describe
(
"ParaEncoder"
,
()
=>
{
it
(
"ParaEncoder Normal Init"
,
()
=>
{
it
(
"ParaEncoder Normal Init"
,
()
=>
{
expect
(
dut
.
numOfWW
).
toBe
(
1
);
expect
(
paraEnc
.
numOfWW
()).
toBe
(
2
);
expect
(
dut
.
codec
).
toBe
(
"h264"
);
expect
(
paraEnc
.
codec
()).
toBe
(
"H264"
);
expect
(
paraEnc
.
mode
()).
toBe
(
ENCODE_MODE
.
SAVE_MEMORY
);
});
});
it
(
"ParaEncoder Invalid Init"
,
()
=>
{
it
(
"ParaEncoder Invalid Init"
,
()
=>
{
try
{
try
{
new
ParaEncoder
(
1
,
1
,
ENCODE_MODE
.
SAVE_MEMORY
);
new
ParaEncoder
(
2
,
1
,
ENCODE_MODE
.
SAVE_MEMORY
);
}
catch
(
err
)
{
}
catch
(
err
)
{}
expect
(
err
.
message
)
.
toBe
(
"typeof(codec) == 'number' failed"
);
}
});
});
it
(
"ParaEncoder Invalid encode mode"
,
()
=>
{
it
(
"ParaEncoder Invalid encode mode"
,
()
=>
{
let
WRONG_MODE
=
0
;
try
{
try
{
new
ParaEncoder
(
1
,
"h264"
,
Symbol
(
"URGENT"
));
new
ParaEncoder
(
1
,
"h264"
,
WRONG_MODE
);
}
catch
(
err
)
{
}
catch
(
err
)
{}
expect
(
err
.
message
)
.
toBe
(
"INVALID ENCODE MODE"
);
}
});
});
it
(
"Encode With ParaEncoder"
,
()
=>
{
});
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment