File size: 4,068 Bytes
92189dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import PrimaryCTAButton from '@/common/components/button/PrimaryCTAButton';
import useMessagesSnackbar from '@/common/components/snackbar/useDemoMessagesSnackbar';
import useFunctionThrottle from '@/common/components/useFunctionThrottle';
import useVideo from '@/common/components/video/editor/useVideo';
import {
  areTrackletObjectsInitializedAtom,
  isStreamingAtom,
  sessionAtom,
  streamingStateAtom,
} from '@/demo/atoms';
import {ChevronRight} from '@carbon/icons-react';
import {useAtom, useAtomValue, useSetAtom} from 'jotai';
import {useCallback, useEffect} from 'react';

export default function TrackAndPlayButton() {
  const video = useVideo();
  const [isStreaming, setIsStreaming] = useAtom(isStreamingAtom);
  const streamingState = useAtomValue(streamingStateAtom);
  const areObjectsInitialized = useAtomValue(areTrackletObjectsInitializedAtom);
  const setSession = useSetAtom(sessionAtom);
  const {enqueueMessage} = useMessagesSnackbar();
  const {isThrottled, maxThrottles, throttle} = useFunctionThrottle(250, 4);

  const isTrackAndPlayDisabled =
    streamingState === 'aborting' || streamingState === 'requesting';

  useEffect(() => {
    function onStreamingStarted() {
      setIsStreaming(true);
    }
    video?.addEventListener('streamingStarted', onStreamingStarted);

    function onStreamingCompleted() {
      enqueueMessage('trackAndPlayComplete');
      setIsStreaming(false);
    }
    video?.addEventListener('streamingCompleted', onStreamingCompleted);

    return () => {
      video?.removeEventListener('streamingStarted', onStreamingStarted);
      video?.removeEventListener('streamingCompleted', onStreamingCompleted);
    };
  }, [video, setIsStreaming, enqueueMessage]);

  const handleTrackAndPlay = useCallback(() => {
    if (isTrackAndPlayDisabled) {
      return;
    }
    if (maxThrottles && isThrottled) {
      enqueueMessage('trackAndPlayThrottlingWarning');
    }

    // Throttling is only applied while streaming because we should
    // only throttle after a user has aborted inference. This way,
    // a user can still quickly abort a stream if they notice the
    // inferred mask is misaligned.
    throttle(
      () => {
        if (!isStreaming) {
          enqueueMessage('trackAndPlayClick');
          video?.streamMasks();
          setSession(previousSession =>
            previousSession == null
              ? previousSession
              : {...previousSession, ranPropagation: true},
          );
        } else {
          video?.abortStreamMasks();
        }
      },
      {enableThrottling: isStreaming},
    );
  }, [
    isTrackAndPlayDisabled,
    isThrottled,
    isStreaming,
    maxThrottles,
    video,
    setSession,
    enqueueMessage,
    throttle,
  ]);

  useEffect(() => {
    const handleKey = (event: KeyboardEvent) => {
      const callback = {
        KeyK: handleTrackAndPlay,
      }[event.code];
      if (callback != null) {
        event.preventDefault();
        callback();
      }
    };
    document.addEventListener('keydown', handleKey);
    return () => {
      document.removeEventListener('keydown', handleKey);
    };
  }, [handleTrackAndPlay]);

  return (
    <PrimaryCTAButton
      disabled={isThrottled || !areObjectsInitialized}
      onClick={handleTrackAndPlay}
      endIcon={isStreaming ? undefined : <ChevronRight size={20} />}>
      {isStreaming ? 'Cancel Tracking' : 'Track objects'}
    </PrimaryCTAButton>
  );
}