@@ -11,6 +11,8 @@ import { Source, VideoSource } from '../../sources';
1111import { VideoClip } from './video' ;
1212import { Composition } from '../../composition' ;
1313import { Keyframe , Timestamp } from '../../models' ;
14+ import { sleep } from '../../utils' ;
15+ import { FrameBuffer } from './buffer' ;
1416
1517import type { MockInstance } from 'vitest' ;
1618
@@ -24,7 +26,7 @@ describe('The Video Clip', () => {
2426
2527 let playFn : MockInstance < ( ) => Promise < void > > ;
2628 let pauseFn : MockInstance < ( ) => Promise < void > > ;
27- let seekFn : MockInstance < ( time : Timestamp ) => Promise < void > > ;
29+ let seekFn : MockInstance < ( arg : number ) => void > ;
2830
2931 const createObjectUrlSpy = vi . spyOn ( Source . prototype as any , 'createObjectURL' ) ;
3032
@@ -95,8 +97,8 @@ describe('The Video Clip', () => {
9597
9698 it ( 'should connect to a track' , async ( ) => {
9799 clip
98- . set ( { offset : 10 , height : '100%' } )
99- . subclip ( 10 , 80 ) ;
100+ . set ( { offset : 6 , height : '100%' } )
101+ . subclip ( 6 , 80 ) ;
100102
101103 const composition = new Composition ( ) ;
102104 const track = composition . createTrack ( 'video' ) ;
@@ -106,17 +108,18 @@ describe('The Video Clip', () => {
106108 await track . add ( clip ) ;
107109
108110 expect ( seekFn ) . toHaveBeenCalledTimes ( 1 ) ;
109- expect ( seekFn . mock . calls [ 0 ] [ 0 ] . seconds ) . toBe ( 1 ) ;
111+ // composition.frame - offset = 24; 24 / 30fps = 0.8
112+ expect ( seekFn . mock . calls [ 0 ] [ 0 ] ) . toBe ( 0.8 ) ;
110113
111114 expect ( clip . state ) . toBe ( 'ATTACHED' ) ;
112- expect ( clip . offset . frames ) . toBe ( 10 ) ;
115+ expect ( clip . offset . frames ) . toBe ( 6 ) ;
113116 expect ( clip . duration . seconds ) . toBe ( 30 ) ;
114117 expect ( clip . height ) . toBe ( '100%' ) ;
115- expect ( clip . range [ 0 ] . frames ) . toBe ( 10 ) ;
118+ expect ( clip . range [ 0 ] . frames ) . toBe ( 6 ) ;
116119 expect ( clip . range [ 1 ] . frames ) . toBe ( 80 ) ;
117120
118- expect ( clip . start . frames ) . toBe ( 20 ) ;
119- expect ( clip . stop . frames ) . toBe ( 90 ) ;
121+ expect ( clip . start . frames ) . toBe ( 12 ) ;
122+ expect ( clip . stop . frames ) . toBe ( 86 ) ;
120123
121124 expect ( track . clips . findIndex ( ( n ) => n . id == clip . id ) ) . toBe ( 0 ) ;
122125 expect ( attachFn ) . toBeCalledTimes ( 1 ) ;
@@ -151,6 +154,7 @@ describe('The Video Clip', () => {
151154 expect ( updateSpy ) . toHaveBeenCalledTimes ( 1 ) ;
152155 expect ( exitSpy ) . toHaveBeenCalledTimes ( 0 ) ;
153156
157+ pauseFn . mockClear ( ) ;
154158 composition . state = 'IDLE' ;
155159 composition . frame = 60 ;
156160 composition . computeFrame ( ) ;
@@ -255,6 +259,60 @@ describe('The Video Clip', () => {
255259
256260 expect ( clip . sprite . texture . uid ) . toBe ( clip . textrues . html5 . uid ) ;
257261 } ) ;
262+
263+ it ( 'should start decoding the video when the seek method is called and the composition is rendering' , async ( ) => {
264+ const composition = new Composition ( ) ;
265+ await composition . add ( clip ) ;
266+
267+ const buffer = new FrameBuffer ( ) ;
268+
269+ Object . defineProperty ( buffer , 'onenqueue' , {
270+ set : ( fn : ( ) => void ) => fn ( )
271+ } ) ;
272+
273+ //@ts -ignore
274+ const decodeSpy = vi . spyOn ( clip , 'decodeVideo' ) . mockReturnValueOnce ( buffer ) ;
275+ composition . state = 'RENDER' ;
276+
277+ await clip . seek ( new Timestamp ( ) ) ;
278+
279+ expect ( decodeSpy ) . toBeCalledTimes ( 1 ) ;
280+ expect ( seekFn . mock . calls [ 0 ] [ 0 ] ) . toBe ( 0 ) ;
281+ } ) ;
282+
283+ it ( 'should calculate the correct demux range' , async ( ) => {
284+ const composition = new Composition ( ) ;
285+ await composition . add ( clip ) ;
286+
287+ clip . subclip ( 6 , 63 ) ;
288+
289+ let [ start , stop ] = ( clip as any ) . demuxRange ;
290+ expect ( start ) . toBe ( 0.2 ) ;
291+ expect ( stop ) . toBe ( 2.1 ) ;
292+
293+ clip . offsetBy ( - 12 )
294+
295+ composition . duration = 30 ;
296+
297+ [ start , stop ] = ( clip as any ) . demuxRange ;
298+ expect ( start ) . toBe ( 0.4 ) ;
299+ expect ( stop ) . toBe ( 1.4 ) ;
300+ } ) ;
301+
302+ it ( 'should be able to cancel decoding' , async ( ) => {
303+ const workerSpy = vi . fn ( ) ;
304+ const bufferSpy = vi . fn ( ) ;
305+
306+ // @ts -ignore
307+ clip . worker = { terminate : workerSpy } ;
308+ // @ts -ignore
309+ clip . buffer = { terminate : bufferSpy } ;
310+
311+ clip . cancelDecoding ( ) ;
312+
313+ expect ( workerSpy ) . toBeCalledTimes ( 1 ) ;
314+ expect ( bufferSpy ) . toBeCalledTimes ( 1 ) ;
315+ } ) ;
258316} ) ;
259317
260318// Blend of different test files
@@ -382,5 +440,9 @@ function mockDimensions(clip: VideoClip, width = 540, height = 680) {
382440}
383441
384442function mockSeek ( clip : VideoClip ) {
385- return vi . spyOn ( clip , 'seek' ) . mockImplementation ( async ( ) => { } ) ;
443+ return vi . spyOn ( clip . element , 'currentTime' , 'set' )
444+ . mockImplementation ( async function ( this : HTMLVideoElement ) {
445+ await sleep ( 1 ) ;
446+ this . dispatchEvent ( new Event ( 'seeked' ) ) ;
447+ } ) ;
386448}
0 commit comments