Skip to content

Commit 0fd582d

Browse files
bmartelGondragoshlomzikrobot-ci-heartexniklub
authored
fix: FIT-31: Ensure media buffers are syncable events that keep audio and video in sync (#7633)
Co-authored-by: bmartel <[email protected]> Co-authored-by: Gondragos <[email protected]> Co-authored-by: Gondragos <[email protected]> Co-authored-by: Sergei Koshevarov <[email protected]> Co-authored-by: Andrew <[email protected]> Co-authored-by: robot-ci-heartex <[email protected]> Co-authored-by: niklub <[email protected]> Co-authored-by: nik <[email protected]>
1 parent 694150e commit 0fd582d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2837
-921
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { useValueRef } from "@humansignal/core/hooks/useValueRef";
2+
import { useCallback } from "react";
3+
4+
export function useRefCallback<T extends (...args: any[]) => any>(callback: T) {
5+
const ref = useValueRef<T>(callback);
6+
7+
return useCallback((...args: Parameters<T>): ReturnType<T> => {
8+
return ref.current(...args);
9+
}, []);
10+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { useRef } from "react";
2+
3+
export function useValueRef<T>(value: T) {
4+
const ref = useRef<T>(value);
5+
ref.current = value;
6+
return ref;
7+
}

web/libs/core/src/lib/utils/feature-flags/flags.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ export const FF_ADJUSTABLE_SPANS = "fflag_feat_front_leap_1973_adjustable_spans_
7373
*/
7474
export const FF_THEME_TOGGLE = "fflag_feat_front_optic_1217_theme_toggle_short";
7575

76+
/**
77+
* Fixes synced audio/video buffering
78+
*/
79+
export const FF_SYNCED_BUFFERING = "fflag_fix_front_fit_31_synced_media_buffering";
80+
7681
/**
7782
* Enables the summary view for annotations
7883
*/

web/libs/core/src/lib/utils/schema/tags.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@
738738
},
739739
"Video": {
740740
"name": "Video",
741-
"description": "Video tag plays a simple video file. Use for video annotation tasks such as classification and transcription.\n\nUse with the following data types: video\n\n### Video format\n\nLabel Studio relies on your web browser to play videos and evaluate the total frame number. So, it's essential that your videos use a format and codecs that are universally supported. To ensure maximum compatibility, we recommend using an MP4 container with video encoded using the H.264 (AVC) codec and audio encoded with AAC. This combination is widely supported across all modern browsers and minimizes issues like incorrect total duration detection or problems with playback. In addition, it's important to convert your videos to a constant frame rate (CFR), ideally around 30 fps, to avoid discrepancies in frame counts and issues with duplicated or missing frames. All audio and video streams from your file must have the same durations; otherwise, you will have extra total frames.\n\nConverting your videos to this recommended format will help ensure that they play smoothly in Label Studio and that the frame rate and duration are correctly recognized for accurate annotations. To convert any video to this format, you can use FFmpeg. For example, the following commands convert an input video to MP4 with H.264 video, AAC audio, and a constant frame rate of 30 fps:\n\n```bash\n# Extract the exact video stream duration in seconds\nDUR=$(ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=nokey=1:noprint_wrappers=1 input.mp4)\n# Re-encode media file to recommended format\nffmpeg -i input_video.mp4 -c:v libx264 -profile:v high -level 4.0 -pix_fmt yuv420p -r 30 -c:a aac -b:a 128k -to $DUR output_video.mp4\n```\n\nIn this command:\n- `-i input_video.mp4` specifies your source video.\n- `-c:v libx264` uses the H.264 codec for video encoding.\n- `-profile:v high -level 4.0` sets compatibility parameters for a broad range of devices.\n- `-pix_fmt yuv420p` ensures the pixel format is compatible with most browsers.\n- `-r 30` forces a constant frame rate of 30 fps. You can also omit the -r option, ffmpeg will save your current frame rate. This is fine if you are 100% certain that your video has a constant frame rate.\n- `-c:a aac -b:a 128k` encodes the audio in AAC at 128 kbps.\n- `-to` stops writing output as soon as the container clock hits your video’s end timestamp, so any extra audio tail is automatically dropped.\n- `output_video.mp4` is the converted video file ready for use in Label Studio.\n\nUsing this FFmpeg command to re-encode your videos will help eliminate playback issues and ensure that Label Studio detects the total video duration accurately, providing a smooth annotation experience.\n\nIt is a good idea to check all parameters of your video using this command:\n```bash\nffprobe -v error -show_format -show_streams -print_format json input.mp4\n```",
741+
"description": "Video tag plays a simple video file. Use for video annotation tasks such as classification and transcription.\n\nUse with the following data types: video\n\n### Video format\n\nLabel Studio relies on your web browser to play videos and evaluate the total frame number. So, it's essential that your videos use a format and codecs that are universally supported. To ensure maximum compatibility, we recommend using an MP4 container with video encoded using the H.264 (AVC) codec and audio encoded with AAC. This combination is widely supported across all modern browsers and minimizes issues like incorrect total duration detection or problems with playback. In addition, it's important to convert your videos to a constant frame rate (CFR), ideally around 30 fps, to avoid discrepancies in frame counts and issues with duplicated or missing frames. All audio and video streams from your file must have the same durations; otherwise, you will have extra total frames.\n\nConverting your videos to this recommended format will help ensure that they play smoothly in Label Studio and that the frame rate and duration are correctly recognized for accurate annotations. To convert any video to this format, you can use FFmpeg. For example, the following commands convert an input video to MP4 with H.264 video, AAC audio, and a constant frame rate of 30 fps:\n\n```bash\n# Extract the exact video stream duration in seconds\nDUR=$(ffprobe -v error -select_streams v:0 -show_entries stream=duration -of default=nokey=1:noprint_wrappers=1 input.mp4)\n# Re-encode media file to recommended format\nffmpeg -i input_video.mp4 -c:v libx264 -profile:v high -level 4.0 -pix_fmt yuv420p -r 30 -c:a aac -b:a 128k -to $DUR output_video.mp4\n```\n\nIn this command:\n- `-i input_video.mp4` specifies your source video.\n- `-c:v libx264` uses the H.264 codec for video encoding.\n- `-profile:v high -level 4.0` sets compatibility parameters for a broad range of devices.\n- `-pix_fmt yuv420p` ensures the pixel format is compatible with most browsers.\n- `-r 30` forces a constant frame rate of 30 fps. You can also omit the -r option, ffmpeg will save your current frame rate. This is fine if you are 100% certain that your video has a constant frame rate.\n- `-c:a aac -b:a 128k` encodes the audio in AAC at 128 kbps.\n- `-to` stops writing output as soon as the container clock hits your video's end timestamp, so any extra audio tail is automatically dropped.\n- `output_video.mp4` is the converted video file ready for use in Label Studio.\n\nUsing this FFmpeg command to re-encode your videos will help eliminate playback issues and ensure that Label Studio detects the total video duration accurately, providing a smooth annotation experience.\n\nIt is a good idea to check all parameters of your video using this command:\n```bash\nffprobe -v error -show_format -show_streams -print_format json input.mp4\n```",
742742
"attrs": {
743743
"name": {
744744
"name": "name",

web/libs/editor/src/components/Timeline/Controls.scss

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,30 @@
11
.timeline-controls {
2+
position: relative;
23
background: var(--color-neutral-background-bold);
34
padding: 4px;
45

6+
&__buffering {
7+
left: 0;
8+
right: 0;
9+
top: 0;
10+
height: 4px;
11+
position: absolute;
12+
background-color: var(--color-primary-content);
13+
overflow: hidden;
14+
15+
&::after {
16+
content: "";
17+
position: absolute;
18+
top: 0;
19+
left: -100%;
20+
width: 25%;
21+
height: 100%;
22+
will-change: left;
23+
background-color: var(--color-primary-content-subtle);
24+
animation: buffering-media 800ms ease-out infinite;
25+
}
26+
}
27+
528
&__counter {
629
height: 36px;
730
min-width: 115px;
@@ -86,7 +109,7 @@
86109
}
87110
}
88111

89-
& + & {
112+
&+& {
90113
border-left: 1px solid var(--color-neutral-border);
91114
}
92115
}
@@ -111,3 +134,13 @@
111134
background: var(--color-neutral-surface);
112135
}
113136
}
137+
138+
@keyframes buffering-media {
139+
0% {
140+
left: -100%;
141+
}
142+
143+
100% {
144+
left: 100%;
145+
}
146+
}

web/libs/editor/src/components/Timeline/Controls.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export const Controls: FC<TimelineControlsProps> = memo(
5050
position,
5151
frameRate = 1024,
5252
playing,
53+
buffering = false,
5354
collapsed,
5455
duration,
5556
extraControls,
@@ -174,6 +175,7 @@ export const Controls: FC<TimelineControlsProps> = memo(
174175

175176
return (
176177
<Block name="timeline-controls" tag={Space} spread style={{ gridAutoColumns: "auto" }}>
178+
{buffering && <Elem name="buffering" aria-label="Buffering Media Source" />}
177179
{mediaType === "audio" ? (
178180
renderControls()
179181
) : (

web/libs/editor/src/components/Timeline/Timeline.scss

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33
background-color: var(--color-neutral-background);
44

55
&__topbar {
6+
padding-bottom: var(--spacing-tight);
67
min-height: 48px;
7-
padding: 6px;
88
display: grid;
99
grid-row-gap: 8px;
1010
align-items: center;
1111
grid-auto-rows: min-content;
1212
grid-template-rows: 1fr;
13-
border-top: 1px solid var(--color-neutral-border);
14-
border-bottom: 1px solid var(--color-neutral-border);
1513
}
1614
}
1715

web/libs/editor/src/components/Timeline/Timeline.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const TimelineComponent: FC<TimelineProps> = ({
2121
altHopSize = 1,
2222
hopSize = altHopSize,
2323
playing = false,
24+
buffering = false,
2425
fullscreen = false,
2526
disableView = false,
2627
defaultStepSize = 10,
@@ -129,6 +130,7 @@ const TimelineComponent: FC<TimelineProps> = ({
129130
position={currentPosition}
130131
frameRate={framerate}
131132
playing={playing}
133+
buffering={buffering}
132134
volume={props.volume}
133135
controls={props.controls}
134136
altHopSize={altHopSize}

web/libs/editor/src/components/Timeline/Types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface TimelineProps<D extends ViewTypes = "frames"> {
1616
mode: D;
1717
framerate: number;
1818
playing: boolean;
19+
buffering?: boolean;
1920
zoom?: number;
2021
volume?: number;
2122
speed?: number;
@@ -184,6 +185,7 @@ export interface TimelineControlsProps {
184185
playing: boolean;
185186
collapsed: boolean;
186187
fullscreen: boolean;
188+
buffering?: boolean;
187189
volume?: number;
188190
speed?: number;
189191
zoom?: number;

web/libs/editor/src/components/VideoCanvas/VideoCanvas.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
padding: 2px 7px;
4040
text-align: center;
4141
background-color: var(--color-neutral-background);
42-
background-image: repeating-linear-gradient(90deg, var(--grape_500) 0, var(--grape_400) 120px, var(--grape_500) 240px);
42+
background-image: repeating-linear-gradient(90deg, var(--color-primary-content) 0, var(--color-primary-content-subtle) 120px, var(--color-primary-content) 240px);
4343
animation: buffering 1.2s linear infinite;
4444
}
4545
}
@@ -72,4 +72,4 @@
7272
100% {
7373
background-position: 240px 0;
7474
}
75-
}
75+
}

0 commit comments

Comments
 (0)