video piece under cursor selection
This commit is contained in:
parent
7b2673d626
commit
2334f305f1
|
|
@ -9,8 +9,8 @@ export const VideoEditorOverlay: React.FC = observer(() => {
|
|||
|
||||
return (
|
||||
<div className='overlay'>
|
||||
{timeToStr(state.video.currentTime)} <br />
|
||||
{state.video.currentFrame}{state.video.isAtMark ? '(mark)' : ''} <br />
|
||||
{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}<br />
|
||||
{timeToStr(state.video.currentTime)}+{state.video.currentFrame}{state.video.isAtMark ? '(mark)' : ''} <br />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
@ -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 (
|
||||
<>
|
||||
{/* <div style={{ height: 300, width: 600 }}> */}
|
||||
<Slider
|
||||
onChange={(values) => {
|
||||
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)}<br/>{mark}</>; return acc;
|
||||
acc[mark] = <>{timeToStr(time)}<br />{mark}</>; return acc;
|
||||
},
|
||||
{} as Record<number, ReactNode>
|
||||
)
|
||||
}
|
||||
trackStyle={{ backgroundColor: 'red', height: 10 }}
|
||||
/>
|
||||
{/* </div> */}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue