1
1
<template >
2
2
<div
3
- class =" row justify-evenly items-center q-pt-lg"
4
- :class =" {'q-pb-lg': $q.screen.lt.md}"
3
+ class =" row justify-between items-center q-pt-lg"
4
+ :class =" {'q-pb-lg q-px -lg': $q.screen.lt.md}"
5
5
>
6
- <q-btn-group flat >
7
- <q-btn
6
+ <div >
7
+ <q-btn-group flat >
8
+ <q-btn
8
9
outline
9
10
:icon =" isPaused ? 'play_arrow' : 'pause'"
10
11
@click =" handlePlayPause"
11
- >
12
- <q-tooltip >{{ isPaused ? 'play (p)' : 'pause (p)' }}</q-tooltip >
13
- </q-btn >
14
- <q-btn
12
+ >
13
+ <q-tooltip >{{ isPaused ? 'play (p)' : 'pause (p)' }}</q-tooltip >
14
+ </q-btn >
15
+ <q-btn
15
16
outline
16
17
icon =" stop"
17
18
:disabled =" !showVideoPlayer"
18
19
@click =" handleStop"
19
- >
20
- <q-tooltip v-if =" showVideoPlayer" >stop</q-tooltip >
21
- </q-btn >
22
- <q-btn
20
+ >
21
+ <q-tooltip v-if =" showVideoPlayer" >stop</q-tooltip >
22
+ </q-btn >
23
+ <q-btn
23
24
outline
24
25
:icon =" showEdit ? 'done' : 'edit'"
25
26
@click =" showEdit = !showEdit"
26
- >
27
- <q-tooltip >{{ showEdit ? 'done' : 'edit' }}</q-tooltip >
28
- </q-btn >
29
- </q-btn-group >
27
+ >
28
+ <q-tooltip >{{ showEdit ? 'done' : 'edit' }}</q-tooltip >
29
+ </q-btn >
30
+ </q-btn-group >
31
+ <q-select
32
+ v-if =" !$q.screen.lt.md"
33
+ class =" q-my-md"
34
+ label =" Playback Rate"
35
+ outlined
36
+ dense
37
+ options-dense
38
+ emit-value
39
+ map-options
40
+ :disable =" !isStopped"
41
+ v-model =" annotationStore.videoPlaybackRate"
42
+ :options =" videoPlaybackRateOptions"
43
+ />
44
+ </div >
45
+ <q-select
46
+ v-if =" $q.screen.lt.md"
47
+ class =" q-my-md"
48
+ style =" width : 162px ;"
49
+ label =" Playback Rate"
50
+ outlined
51
+ dense
52
+ options-dense
53
+ emit-value
54
+ map-options
55
+ :disable =" !isStopped"
56
+ v-model =" annotationStore.videoPlaybackRate"
57
+ :options =" videoPlaybackRateOptions"
58
+ />
30
59
<div
31
- class =" col-grow q-px-lg "
32
- :class =" [{'col-12': $q.screen.lt.md}]"
33
- :style =" {'order': !$q.screen.lt.md ? 0 : -1}"
60
+ class =" col-grow"
61
+ :class =" [{'col-12': $q.screen.lt.md, 'q-px-lg': ! $q.screen.lt.md}]"
62
+ :style =" {'order': !$q.screen.lt.md ? 0 : -1}"
34
63
>
35
64
<q-range
36
- class =" custom-range"
37
- :class =" {'hide-right-marker': currentFocus === 'left', 'hide-left-marker': currentFocus === 'right'}"
38
- :style =" rangeStyle"
39
- label-always
40
- drag-range
41
- snap
42
- track-size =" 8px"
43
- :min =" 0"
44
- :max =" annotationStore.video.frames - 1"
45
- :step =" 1"
46
- left-label-text-color =" blue-grey-1"
47
- right-label-text-color =" blue-grey-1"
48
- left-label-color =" primary"
49
- right-label-color =" primary"
50
- :left-label-value =" 'L: ' + currentFrameRange.min + ' | ' + utils.toFixed2(utils.index2time(currentFrameRange.min)) + ' s'"
51
- :right-label-value =" 'R: ' + currentFrameRange.max + ' | ' + utils.toFixed2(utils.index2time(currentFrameRange.max)) + ' s'"
52
- :model-value =" currentFrameRange"
53
- @update:model-value =" handleInput"
65
+ class =" custom-range"
66
+ :class =" {'hide-right-marker': currentFocus === 'left', 'hide-left-marker': currentFocus === 'right'}"
67
+ :style =" rangeStyle"
68
+ label-always
69
+ drag-range
70
+ snap
71
+ track-size =" 8px"
72
+ :min =" 0"
73
+ :max =" annotationStore.video.frames - 1"
74
+ :step =" 1"
75
+ left-label-text-color =" blue-grey-1"
76
+ right-label-text-color =" blue-grey-1"
77
+ left-label-color =" primary"
78
+ right-label-color =" primary"
79
+ :left-label-value =" 'L: ' + currentFrameRange.min + ' | ' + utils.toFixed2(utils.index2time(currentFrameRange.min)) + ' s'"
80
+ :right-label-value =" 'R: ' + currentFrameRange.max + ' | ' + utils.toFixed2(utils.index2time(currentFrameRange.max)) + ' s'"
81
+ :model-value =" currentFrameRange"
82
+ @update:model-value =" handleInput"
54
83
/>
55
84
</div >
56
85
<q-btn-group flat >
57
86
<q-btn
58
- outline
59
- icon =" keyboard_arrow_left"
60
- @click =" handlePreviousKeyframe"
87
+ outline
88
+ icon =" keyboard_arrow_left"
89
+ @click =" handlePreviousKeyframe"
61
90
>
62
91
<q-tooltip >previous keyframe (<)</q-tooltip >
63
92
</q-btn >
64
93
<q-btn
65
- outline
66
- icon =" gps_fixed"
67
- @click =" handleNearestKeyframe"
94
+ outline
95
+ icon =" gps_fixed"
96
+ @click =" handleNearestKeyframe"
68
97
>
69
98
<q-tooltip >locate nearest keyframe</q-tooltip >
70
99
</q-btn >
71
100
<q-btn
72
- outline
73
- icon =" keyboard_arrow_right"
74
- @click =" handleNextKeyframe"
101
+ outline
102
+ icon =" keyboard_arrow_right"
103
+ @click =" handleNextKeyframe"
75
104
>
76
105
<q-tooltip >next keyframe (>)</q-tooltip >
77
106
</q-btn >
@@ -91,6 +120,7 @@ const annotationStore = useAnnotationStore()
91
120
92
121
// left buttons
93
122
const isPaused = ref (true )
123
+ const isStopped = ref (true )
94
124
const showVideoPlayer = ref (false )
95
125
const showEdit = ref (false )
96
126
let videoPlayTimeout
@@ -100,10 +130,11 @@ let lastLeftCurrentFrame
100
130
const play = () => {
101
131
const videoPlayer = document .getElementById (' video-player' )
102
132
isPaused .value = false
133
+ isStopped .value = false
103
134
videoPlayer .playbackRate = annotationStore .videoPlaybackRate
104
135
videoPlayer .play ()
105
136
const duration = (utils .index2time (annotationStore .rightCurrentFrame ) - videoPlayer .currentTime ) * 1000 /
106
- videoPlayer .playbackRate
137
+ videoPlayer .playbackRate
107
138
videoPlayTimeout = setTimeout (() => {
108
139
handleStop ()
109
140
}, duration)
@@ -125,6 +156,7 @@ const stop = () => {
125
156
videoPlayer .currentTime = utils .index2time (lastLeftCurrentFrame)
126
157
showVideoPlayer .value = false
127
158
isPaused .value = true
159
+ isStopped .value = true
128
160
clearTimeout (videoPlayTimeout)
129
161
clearInterval (videoPlayInterval)
130
162
}
@@ -149,6 +181,34 @@ const handleStop = () => {
149
181
annotationStore .leftCurrentFrame = lastLeftCurrentFrame
150
182
}
151
183
184
+ // options
185
+ const videoPlaybackRateOptions = [
186
+ {
187
+ label: ' 0.5x' ,
188
+ value: 0.5 ,
189
+ },
190
+ {
191
+ label: ' 0.75x' ,
192
+ value: 0.75 ,
193
+ },
194
+ {
195
+ label: ' 1.0x' ,
196
+ value: 1.0 ,
197
+ },
198
+ {
199
+ label: ' 1.25x' ,
200
+ value: 1.25 ,
201
+ },
202
+ {
203
+ label: ' 1.5x' ,
204
+ value: 1.5 ,
205
+ },
206
+ {
207
+ label: ' 2.0x' ,
208
+ value: 2.0 ,
209
+ },
210
+ ]
211
+
152
212
// right buttons
153
213
const nearestKeyframe = currentFrame => {
154
214
let min = annotationStore .video .frames
@@ -197,7 +257,7 @@ const handleNearestKeyframe = () => {
197
257
} else {
198
258
annotationStore .leftCurrentFrame = leftCurrentKeyFrame
199
259
annotationStore .rightCurrentFrame = annotationStore .keyframeList [leftCurrentKeyFrameIndex + 1 ] ||
200
- leftCurrentKeyFrame
260
+ leftCurrentKeyFrame
201
261
}
202
262
}
203
263
const handleNextKeyframe = () => { // base on left most one
@@ -208,17 +268,17 @@ const handleNextKeyframe = () => { // base on left most one
208
268
const lastIndex = annotationStore .keyframeList .length - 1
209
269
if (leftCurrentKeyFrameIndex >= lastIndex || rightCurrentKeyFrameIndex >= lastIndex) {
210
270
annotationStore .leftCurrentFrame = lastIndex - 1 >= 0
211
- ? annotationStore .keyframeList [lastIndex - 1 ]
212
- : annotationStore .keyframeList [lastIndex]
271
+ ? annotationStore .keyframeList [lastIndex - 1 ]
272
+ : annotationStore .keyframeList [lastIndex]
213
273
annotationStore .rightCurrentFrame = annotationStore .keyframeList [lastIndex]
214
274
} else if (leftCurrentKeyFrameIndex === rightCurrentKeyFrameIndex) {
215
275
annotationStore .leftCurrentFrame = leftCurrentKeyFrame
216
276
annotationStore .rightCurrentFrame = annotationStore .keyframeList [leftCurrentKeyFrameIndex + 1 ]
217
277
} else if (leftCurrentKeyFrameIndex < rightCurrentKeyFrameIndex) {
218
278
if (leftCurrentKeyFrameIndex + 2 > lastIndex) {
219
279
annotationStore .leftCurrentFrame = lastIndex - 1 >= 0
220
- ? annotationStore .keyframeList [lastIndex - 1 ]
221
- : annotationStore .keyframeList [lastIndex]
280
+ ? annotationStore .keyframeList [lastIndex - 1 ]
281
+ : annotationStore .keyframeList [lastIndex]
222
282
annotationStore .rightCurrentFrame = annotationStore .keyframeList [lastIndex]
223
283
} else {
224
284
annotationStore .leftCurrentFrame = annotationStore .keyframeList [leftCurrentKeyFrameIndex + 1 ]
@@ -263,7 +323,7 @@ const moveRange = interval => {
263
323
}
264
324
} else {
265
325
if (Math .max (annotationStore .leftCurrentFrame , annotationStore .rightCurrentFrame ) + interval
266
- <= annotationStore .video .frames ) {
326
+ <= annotationStore .video .frames ) {
267
327
annotationStore .leftCurrentFrame += interval
268
328
annotationStore .rightCurrentFrame += interval
269
329
}
@@ -319,14 +379,14 @@ const handleKeydown = event => {
319
379
currentFocus .value = {
320
380
left: ' right' ,
321
381
range: ' left' ,
322
- right: ' range'
382
+ right: ' range' ,
323
383
}[currentFocus .value ]
324
384
event .preventDefault ()
325
385
} else if (event .code === ' ArrowDown' ) {
326
386
currentFocus .value = {
327
387
left: ' range' ,
328
388
range: ' right' ,
329
- right: ' left'
389
+ right: ' left' ,
330
390
}[currentFocus .value ]
331
391
event .preventDefault ()
332
392
} else if (event .code === ' PageUp' ) {
@@ -369,7 +429,7 @@ const currentFrameRange = computed({
369
429
get : () => {
370
430
return {
371
431
min: annotationStore .leftCurrentFrame ,
372
- max: annotationStore .rightCurrentFrame
432
+ max: annotationStore .rightCurrentFrame ,
373
433
}
374
434
},
375
435
set : (value ) => {
@@ -378,7 +438,7 @@ const currentFrameRange = computed({
378
438
}
379
439
annotationStore .leftCurrentFrame = value .min
380
440
annotationStore .rightCurrentFrame = value .max
381
- }
441
+ },
382
442
})
383
443
const { rangeStyle } = frameIndicator ()
384
444
</script >
0 commit comments