diff --git a/src/components/VideoEditorOverlay.tsx b/src/components/VideoEditorOverlay.tsx
index accc324..20902d9 100644
--- a/src/components/VideoEditorOverlay.tsx
+++ b/src/components/VideoEditorOverlay.tsx
@@ -9,8 +9,8 @@ export const VideoEditorOverlay: React.FC = observer(() => {
return (
- {timeToStr(state.video.currentTime)}
- {state.video.currentFrame}{state.video.isAtMark ? '(mark)' : ''}
+ {timeToStr(state.video.frameToTime(state.video.progress.start))}+{state.video.progress.start} to {timeToStr(state.video.frameToTime(state.video.progress.end))}+{state.video.progress.end}
+ {timeToStr(state.video.currentTime)}+{state.video.currentFrame}{state.video.isAtMark ? '(mark)' : ''}
);
});
\ No newline at end of file
diff --git a/src/components/VideoProgress.tsx b/src/components/VideoProgress.tsx
index 4660308..a408746 100644
--- a/src/components/VideoProgress.tsx
+++ b/src/components/VideoProgress.tsx
@@ -8,35 +8,54 @@ import { timeToStr } from '../utils/time';
export const VideoProgress: React.FC = observer(() => {
+ const values = state.video.progress.values;
+
+ // console.dir(JSON.stringify({
+ // count: state.video.progress.count,
+ // values,
+ // }));
+
+ function findChangedValue(changedValues: number[]): number {
+ // we never know which handle rc-slider decides to move
+ // so whatever handle has changed, it must be our target
+ for (const value of changedValues as number[]) {
+ if (!values.includes(value))
+ return value;
+ }
+ return changedValues[0];
+ }
+
return (
<>
{/* */}
{
- state.video.seekToTime(values as number);
- // console.log('Change:', JSON.stringify(values));
+ range
+ allowCross={true}
+ onChange={(changedValues) => {
+ const changedValue = findChangedValue(changedValues as number[]);
+ console.log(`Change: ${JSON.stringify(changedValues)}, ${changedValue}`);
+ state.video.seekToFrame(changedValue);
}}
// onChangeComplete={(v) => {
// console.log('AfterChange:', v);
// }}
min={0}
- max={state.video.metadata ? state.video.metadata?.duration : 0}
- value={state.video.currentTime}
- included={false}
+ max={state.video.lastFrame}
+ count={state.video.progress.count}
+ value={values}
+ // included={false}
keyboard={false}
- step={state.video.metadata ? 1 / state.video.metadata?.frameRate : undefined}
+ step={1}
marks={
state.video.marks.reduce(
(acc, mark) => {
const time = state.video.frameToTime(mark);
- acc[time] = <>{timeToStr(time)}
{mark}>; return acc;
+ acc[mark] = <>{timeToStr(time)}
{mark}>; return acc;
},
{} as Record
)
}
- trackStyle={{ backgroundColor: 'red', height: 10 }}
/>
- {/*
*/}
>
);
});
diff --git a/src/state/videoEditor.ts b/src/state/videoEditor.ts
index 9b1aeff..b3ccaba 100644
--- a/src/state/videoEditor.ts
+++ b/src/state/videoEditor.ts
@@ -1,4 +1,5 @@
import { action, computed, makeObservable, observable } from 'mobx';
+import { VideoEditorProgressState } from './videoEditorProgress';
export type VideoMetadata = {
frameRate: number;
@@ -7,6 +8,9 @@ export type VideoMetadata = {
};
export class VideoEditorState {
+
+ public progress = new VideoEditorProgressState(this);
+
@observable
public url: string | undefined;
@@ -40,6 +44,11 @@ export class VideoEditorState {
return (frame + 0.4) / this.metadata.frameRate + this.metadata.firstFrameTime;
}
+ @computed
+ get lastFrame(): number {
+ return this.metadata ? this.timeToFrame(this.metadata.duration) : 0;
+ }
+
@computed
get currentFrame(): number {
return this.timeToFrame(this.currentTime);
@@ -66,7 +75,7 @@ export class VideoEditorState {
@action
setMetadata(metadata: VideoMetadata) {
this.metadata = metadata;
- this.marks = [0, this.timeToFrame(metadata.duration)];
+ this.marks = [0, this.lastFrame];
}
@action
@@ -97,12 +106,7 @@ export class VideoEditorState {
if (!this.metadata)
return;
- const currentFrame = this.currentFrame.valueOf();
- const marks = this.marks.filter((m) => m < currentFrame);
- const prevMark = marks.length ? marks[marks.length - 1] : 0;
- // console.dir({ currentFrame, marks, prevMark });
- if (marks)
- this.seekToFrame(prevMark);
+ this.seekToFrame(this.getPrevMark(this.currentFrame));
}
@action
@@ -110,12 +114,22 @@ export class VideoEditorState {
if (!this.metadata)
return;
- const currentFrame = this.currentFrame.valueOf();
- const marks = this.marks.filter((m) => m > currentFrame);
- // console.dir({ currentFrame, marks });
- if (marks.length)
- this.seekToFrame(marks[0]);
- else
- this.seekToTime(this.metadata?.duration);
+ this.seekToFrame(this.getNextMark(this.currentFrame));
+ }
+
+ public getPrevMark(frame: number): number {
+ if (!this.metadata)
+ return frame;
+
+ const marks = this.marks.filter((m) => m < frame);
+ return marks.length ? marks[marks.length - 1] : 0;
+ }
+
+ public getNextMark(frame: number): number {
+ if (!this.metadata)
+ return frame;
+
+ const marks = this.marks.filter((m) => m > frame);
+ return marks.length ? marks[0] : this.lastFrame;
}
}
\ No newline at end of file
diff --git a/src/state/videoEditorProgress.ts b/src/state/videoEditorProgress.ts
new file mode 100644
index 0000000..ff535f0
--- /dev/null
+++ b/src/state/videoEditorProgress.ts
@@ -0,0 +1,35 @@
+import { action, computed, makeObservable, observable } from 'mobx';
+import { VideoEditorState } from './videoEditor';
+
+export type VideoMetadata = {
+ frameRate: number;
+ firstFrameTime: number;
+ duration: number;
+};
+
+export class VideoEditorProgressState {
+
+ @observable
+ public count: number = 2;
+
+ constructor(
+ private readonly editor: VideoEditorState
+ ) {
+ makeObservable(this);
+ }
+
+ @computed
+ get values(): number[] {
+ return [this.start, this.editor.currentFrame, this.end];
+ }
+
+ @computed
+ public get start(): number {
+ return this.editor.getPrevMark(this.editor.currentFrame);
+ }
+
+ @computed
+ public get end(): number {
+ return this.editor.getNextMark(this.editor.currentFrame);
+ }
+}
\ No newline at end of file