Skip to content

Commit

Permalink
implement autoplay for Video and Audio (#4453)
Browse files Browse the repository at this point in the history
  • Loading branch information
pngwn committed Jun 8, 2023
1 parent 6888e30 commit 3d334e2
Show file tree
Hide file tree
Showing 12 changed files with 58 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,7 @@
## New Features:

- Add `start_recording` and `stop_recording` events to `Video` and `Audio` components by [@pngwn](https://github.com/pngwn) in [PR 4422](https://github.com/gradio-app/gradio/pull/4422)
- Add `autoplay` kwarg to `Video` and `Audio` components by [@pngwn](https://github.com/pngwn) in [PR 4453](https://github.com/gradio-app/gradio/pull/4453)

## Bug Fixes:

Expand Down
10 changes: 10 additions & 0 deletions gradio/components.py
Expand Up @@ -2172,6 +2172,7 @@ def __init__(
elem_classes: list[str] | str | None = None,
mirror_webcam: bool = True,
include_audio: bool | None = None,
autoplay: bool = False,
**kwargs,
):
"""
Expand All @@ -2195,6 +2196,7 @@ def __init__(
include_audio: Whether the component should record/retain the audio track for a video. By default, audio is excluded for webcam videos and included for uploaded videos.
"""
self.format = format
self.autoplay = autoplay
valid_sources = ["upload", "webcam"]
if source not in valid_sources:
raise ValueError(
Expand Down Expand Up @@ -2231,6 +2233,7 @@ def get_config(self):
"width": self.width,
"mirror_webcam": self.mirror_webcam,
"include_audio": self.include_audio,
"autoplay": self.autoplay,
**IOComponent.get_config(self),
}

Expand All @@ -2250,6 +2253,7 @@ def update(
min_width: int | None = None,
interactive: bool | None = None,
visible: bool | None = None,
autoplay: bool | None = None,
):
return {
"source": source,
Expand All @@ -2263,6 +2267,7 @@ def update(
"interactive": interactive,
"visible": visible,
"value": value,
"autoplay": autoplay,
"__type__": "update",
}

Expand Down Expand Up @@ -2518,6 +2523,7 @@ def __init__(
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
format: Literal["wav", "mp3"] = "wav",
autoplay: bool = False,
**kwargs,
):
"""
Expand Down Expand Up @@ -2572,12 +2578,14 @@ def __init__(
)
TokenInterpretable.__init__(self)
self.format = format
self.autoplay = autoplay

def get_config(self):
return {
"source": self.source,
"value": self.value,
"streaming": self.streaming,
"autoplay": self.autoplay,
**IOComponent.get_config(self),
}

Expand All @@ -2598,6 +2606,7 @@ def update(
min_width: int | None = None,
interactive: bool | None = None,
visible: bool | None = None,
autoplay: bool | None = None,
):
return {
"source": source,
Expand All @@ -2609,6 +2618,7 @@ def update(
"interactive": interactive,
"visible": visible,
"value": value,
"autoplay": autoplay,
"__type__": "update",
}

Expand Down
1 change: 0 additions & 1 deletion js/_spaces-test/src/lib/EndpointInputs.svelte
Expand Up @@ -20,7 +20,6 @@
if (!files) return;
const _files = Array.from(files);
request_data[i] = files.length === 1 ? _files[0] : _files;
console.log(request_data);
}
</script>

Expand Down
3 changes: 3 additions & 0 deletions js/app/src/components/Audio/Audio.svelte
Expand Up @@ -35,6 +35,7 @@
export let scale: number = 1;
export let min_width: number | undefined = undefined;
export let loading_status: LoadingStatus;
export let autoplay: boolean = false;
let _value: null | FileData;
$: _value = normalise_file(value, root, root_url);
Expand Down Expand Up @@ -75,6 +76,7 @@
{source}
{pending}
{streaming}
{autoplay}
on:edit
on:play
on:pause
Expand All @@ -93,6 +95,7 @@
</Audio>
{:else}
<StaticAudio
{autoplay}
{show_label}
value={_value}
name={_value?.name || "audio_file"}
Expand Down
4 changes: 4 additions & 0 deletions js/app/src/components/Video/Video.svelte
Expand Up @@ -30,6 +30,8 @@
export let scale: number = 1;
export let min_width: number | undefined = undefined;
export let mode: "static" | "dynamic";
export let autoplay: boolean = false;
let _video: FileData | null = null;
let _subtitle: FileData | null = null;
Expand Down Expand Up @@ -91,6 +93,7 @@
subtitle={_subtitle}
{label}
{show_label}
{autoplay}
on:play
on:pause
on:stop
Expand All @@ -111,6 +114,7 @@
{source}
{mirror_webcam}
{include_audio}
{autoplay}
on:clear
on:play
on:pause
Expand Down
13 changes: 12 additions & 1 deletion js/audio/src/Audio.svelte
Expand Up @@ -24,6 +24,7 @@
export let source: "microphone" | "upload" | "none";
export let pending: boolean = false;
export let streaming: boolean = false;
export let autoplay: boolean;
// TODO: make use of this
// export let type: "normal" | "numpy" = "normal";
Expand All @@ -34,7 +35,7 @@
let header: Uint8Array | undefined = undefined;
let pending_stream: Array<Uint8Array> = [];
let submit_pending_stream_on_pending_end: boolean = false;
let player;
let player: HTMLAudioElement;
let inited = false;
let crop_values = [0, 100];
const STREAM_TIMESLICE = 500;
Expand Down Expand Up @@ -259,8 +260,18 @@
dispatch("end");
}
let old_val: any;
function value_has_changed(val: any) {
if (val === old_val) return false;
else {
old_val = val;
return true;
}
}
export let dragging = false;
$: dispatch("drag", dragging);
$: autoplay && player && value_has_changed(value?.data) && player.play();
</script>

<BlockLabel
Expand Down
15 changes: 15 additions & 0 deletions js/audio/src/StaticAudio.svelte
Expand Up @@ -17,6 +17,7 @@
export let label: string;
export let name: string;
export let show_label: boolean = true;
export let autoplay: boolean;
const dispatch = createEventDispatcher<{
change: AudioData;
Expand All @@ -32,6 +33,19 @@
data: value?.data
});
let el: HTMLAudioElement;
let old_val: any;
function value_has_changed(val: any) {
if (val === old_val) return false;
else {
old_val = val;
return true;
}
}
$: autoplay && el && value_has_changed(value) && el.play();
function handle_ended() {
dispatch("stop");
dispatch("end");
Expand All @@ -45,6 +59,7 @@
</Empty>
{:else}
<audio
bind:this={el}
controls
preload="metadata"
src={value.data}
Expand Down
24 changes: 4 additions & 20 deletions js/video/src/Player.svelte
Expand Up @@ -5,6 +5,7 @@
export let src: string;
export let subtitle: string | null = null;
export let mirror: boolean;
export let autoplay: boolean;
const dispatch = createEventDispatcher<{
play: undefined;
Expand All @@ -18,15 +19,6 @@
let paused: boolean = true;
let video: HTMLVideoElement;
let show_controls = true;
let show_controls_timeout: NodeJS.Timeout;
function video_move() {
clearTimeout(show_controls_timeout);
show_controls_timeout = setTimeout(() => (show_controls = false), 500);
show_controls = true;
}
function handleMove(e: TouchEvent | MouseEvent) {
if (!duration) return;
Expand Down Expand Up @@ -79,22 +71,17 @@
}
async function checkforVideo() {
transition = "0s";
await tick();
wrap_opacity = 0.8;
opacity = 0;
await tick();
var b = setInterval(async () => {
if (video.readyState >= 3) {
video.currentTime = 9999;
paused = true;
transition = "0.2s";
setTimeout(async () => {
video.currentTime = 0.0;
opacity = 1;
wrap_opacity = 1;
}, 50);
clearInterval(b);
}
Expand All @@ -105,23 +92,20 @@
checkforVideo();
}
let opacity: number = 0;
let wrap_opacity: number = 0;
let transition: string = "0.5s";
$: src && _load();
function handle_end() {
dispatch("stop");
dispatch("end");
}
$: autoplay && video && src && video.play();
</script>

<div class="wrap">
<video
{src}
preload="auto"
on:mousemove={video_move}
on:click={play_pause}
on:play
on:pause
Expand Down
3 changes: 3 additions & 0 deletions js/video/src/StaticVideo.svelte
Expand Up @@ -10,6 +10,8 @@
export let subtitle: FileData | null = null;
export let label: string | undefined = undefined;
export let show_label: boolean = true;
export let autoplay: boolean;
let old_value: FileData | null = null;
let old_subtitle: FileData | null = null;
Expand Down Expand Up @@ -49,6 +51,7 @@
<Player
src={value.data}
subtitle={subtitle?.data}
{autoplay}
on:play
on:pause
on:ended
Expand Down
2 changes: 2 additions & 0 deletions js/video/src/Video.svelte
Expand Up @@ -16,6 +16,7 @@
export let show_label: boolean = true;
export let mirror_webcam: boolean = false;
export let include_audio: boolean;
export let autoplay: boolean;
const dispatch = createEventDispatcher<{
change: any;
Expand Down Expand Up @@ -68,6 +69,7 @@
{#if playable()}
<!-- svelte-ignore a11y-media-has-caption -->
<Player
{autoplay}
src={value.data}
subtitle={subtitle?.data}
on:play
Expand Down
1 change: 1 addition & 0 deletions test/test_blocks.py
Expand Up @@ -1154,6 +1154,7 @@ def test_with_generic_update(self):
}
)
assert specific_update == {
"autoplay": None,
"source": None,
"label": None,
"show_label": None,
Expand Down
3 changes: 3 additions & 0 deletions test/test_components.py
Expand Up @@ -822,6 +822,7 @@ def test_component_functions(self):

audio_input = gr.Audio(label="Upload Your Audio")
assert audio_input.get_config() == {
"autoplay": False,
"source": "upload",
"name": "audio",
"streaming": False,
Expand Down Expand Up @@ -856,6 +857,7 @@ def test_component_functions(self):
audio_output = gr.Audio(type="filepath")
assert filecmp.cmp(y_audio.name, audio_output.postprocess(y_audio.name)["name"])
assert audio_output.get_config() == {
"autoplay": False,
"name": "audio",
"streaming": False,
"show_label": True,
Expand Down Expand Up @@ -1306,6 +1308,7 @@ def test_component_functions(self):

video_input = gr.Video(label="Upload Your Video")
assert video_input.get_config() == {
"autoplay": False,
"source": "upload",
"name": "video",
"show_label": True,
Expand Down

0 comments on commit 3d334e2

Please sign in to comment.