1
1
import Vue from "vue" ;
2
2
import uuidv4 from "uuid/v4" ;
3
+ import store from "../" ;
3
4
4
5
const state = { } ;
5
6
6
7
const getters = {
7
- video : state => id => state [ id ]
8
+ video : state => id => state [ id ] ?. outputContext ?. context . canvas
8
9
} ;
9
10
10
11
const actions = {
11
- createVideoFromPath ( { commit } , { path : filePath } ) {
12
+ createVideoFromPath ( { rootState , commit } , { path : filePath } ) {
12
13
const id = uuidv4 ( ) ;
13
- const path = `modv://${ filePath } ` ;
14
+ const path = `modv://${ rootState . media . path } ${ filePath } ` ;
14
15
15
16
if ( typeof window !== "undefined" ) {
16
17
self . postMessage ( {
@@ -24,19 +25,85 @@ const actions = {
24
25
return { id } ;
25
26
} ,
26
27
27
- assignVideoStream ( { commit } , { id, stream, width, height } ) {
28
- commit ( "UPDATE_VIDEO" , { id, stream, width, height } ) ;
28
+ async assignVideoStream ( { commit } , { id, stream, width, height } ) {
29
+ const frameReader = stream . getReader ( ) ;
30
+ const outputContext = await store . dispatch ( "outputs/getAuxillaryOutput" , {
31
+ name : state [ id ] . path ,
32
+ options : {
33
+ desynchronized : true
34
+ } ,
35
+ group : "videos" ,
36
+ reactToResize : false ,
37
+ width,
38
+ height
39
+ } ) ;
40
+
41
+ frameReader . read ( ) . then ( function processFrame ( { done, value : frame } ) {
42
+ const { stream, needsRemoval } = state [ id ] ;
43
+ if ( done ) {
44
+ return ;
45
+ }
46
+
47
+ // NOTE: all paths below must call frame.close(). Otherwise, the GC won't
48
+ // be fast enough to recollect VideoFrames, and decoding can stall.
49
+
50
+ if ( needsRemoval ) {
51
+ // TODO: There might be a more elegant way of closing a stream, or other
52
+ // events to listen for - do we need to use frameReader.cancel(); somehow?
53
+ frameReader . releaseLock ( ) ;
54
+ stream . cancel ( ) ;
55
+
56
+ frame . close ( ) ;
57
+
58
+ commit ( "REMOVE_VIDEO" , { id } ) ;
59
+
60
+ if ( typeof window !== "undefined" ) {
61
+ self . postMessage ( {
62
+ type : "removeWebcodecVideo" ,
63
+ id
64
+ } ) ;
65
+ }
66
+ return ;
67
+ }
68
+
69
+ // Processing on 'frame' goes here!
70
+ // E.g. this is where encoding via a VideoEncoder could be set up, or
71
+ // rendering to an OffscreenCanvas.
72
+
73
+ outputContext . context . drawImage ( frame , 0 , 0 ) ;
74
+ frame . close ( ) ;
75
+
76
+ frameReader . read ( ) . then ( processFrame ) ;
77
+ } ) ;
78
+
79
+ commit ( "UPDATE_VIDEO" , {
80
+ id,
81
+ stream,
82
+ width,
83
+ height,
84
+ frameReader,
85
+ outputContext,
86
+ needsRemoval : false
87
+ } ) ;
88
+ } ,
89
+
90
+ async removeVideoById ( { commit } , { id } ) {
91
+ commit ( "UPDATE_VIDEO" , { id, needsRemoval : true } ) ;
29
92
}
30
93
} ;
31
94
32
95
const mutations = {
33
96
CREATE_VIDEO ( state , { id, path } ) {
34
- Vue . set ( state , id , path ) ;
97
+ Vue . set ( state , id , { path } ) ;
35
98
} ,
36
99
37
100
UPDATE_VIDEO ( state , video ) {
38
101
const { id } = video ;
39
102
state [ id ] = { ...state [ id ] , ...video } ;
103
+ } ,
104
+
105
+ REMOVE_VIDEO ( state , { id } ) {
106
+ delete state [ id ] ;
40
107
}
41
108
} ;
42
109
0 commit comments