enhancement: record audio and video from webcam simultaneously (#2721)

* Recording Audio and Video from webcam simultaneously

* Add include_audio option in Video component

* Update gradio/components.py

Co-authored-by: pngwn <hello@pngwn.io>

* Update CHANGELOG.md

Co-authored-by: pngwn <hello@pngwn.io>

* updated include_audio default behavior

Co-authored-by: Mandar Gogate <9411881+MandarGogate@users.noreply.github.com>
Co-authored-by: pngwn <hello@pngwn.io>
This commit is contained in:
Jean Ribeiro 2022-12-26 15:56:17 -03:00 committed by GitHub
parent 066adf1a9d
commit 24f413c4b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 28 additions and 3 deletions

View File

@ -405,6 +405,7 @@ No changes to highlight.
* Make try examples button more prominent by [@aliabd](https://github.com/aliabd) in [PR 2705](https://github.com/gradio-app/gradio/pull/2705)
* Fix id clashes in docs by [@aliabd](https://github.com/aliabd) in [PR 2713](https://github.com/gradio-app/gradio/pull/2713)
* Fix typos in guide docs by [@andridns](https://github.com/andridns) in [PR 2722](https://github.com/gradio-app/gradio/pull/2722)
* Add option to `include_audio` in Video component. When `True`, for `source="webcam"` this will record audio and video, for `source="upload"` this will retain the audio in an uploaded video by [@mandargogate](https://github.com/MandarGogate) in [PR 2721](https://github.com/gradio-app/gradio/pull/2721)
## Contributors Shoutout:
* [@andridns](https://github.com/andridns) made their first contribution in [PR 2722](https://github.com/gradio-app/gradio/pull/2722)!

View File

@ -1653,6 +1653,7 @@ class Video(
visible: bool = True,
elem_id: Optional[str] = None,
mirror_webcam: bool = True,
include_audio: Optional[bool] = None,
**kwargs,
):
"""
@ -1666,7 +1667,8 @@ class Video(
interactive: if True, will allow users to upload a video; if False, can only be used to display videos. If not provided, this is inferred based on whether the component is used as an input or output.
visible: If False, component will be hidden.
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
mirror_webcam: If True webcma will be mirrored. Default is True.
mirror_webcam: If True webcam will be mirrored. Default is True.
include_audio: If False, component will not record or retain the audio track for a video.
"""
self.format = format
valid_sources = ["upload", "webcam"]
@ -1676,6 +1678,9 @@ class Video(
)
self.source = source
self.mirror_webcam = mirror_webcam
self.include_audio = (
include_audio if include_audio is not None else source == "upload"
)
TempFileManager.__init__(self)
IOComponent.__init__(
self,
@ -1694,6 +1699,7 @@ class Video(
"source": self.source,
"value": self.value,
"mirror_webcam": self.mirror_webcam,
"include_audio": self.include_audio,
**IOComponent.get_config(self),
}
@ -1746,7 +1752,8 @@ class Video(
flip = self.source == "webcam" and self.mirror_webcam
if modify_format or flip:
format = f".{self.format if modify_format else uploaded_format}"
output_options = ["-vf", "hflip", "-c:a", "copy"] if flip else None
output_options = ["-vf", "hflip", "-c:a", "copy"] if flip else []
output_options += ["-an"] if not self.include_audio else []
flip_suffix = "_flip" if flip else ""
output_file_name = str(
file_name.with_name(f"{file_name.stem}{flip_suffix}{format}")
@ -1759,6 +1766,14 @@ class Video(
)
ff.run()
return output_file_name
elif not self.include_audio:
output_file_name = str(file_name.with_name(f"muted_{file_name.name}"))
ff = FFmpeg(
inputs={str(file_name): None},
outputs={output_file_name: ["-an"]},
)
ff.run()
return output_file_name
else:
return str(file_name)

View File

@ -333,6 +333,7 @@ class PlayableVideo(components.Video):
visible: bool = True,
elem_id: Optional[str] = None,
mirror_webcam: bool = True,
include_audio: Optional[bool] = None,
**kwargs,
):
super().__init__(
@ -345,6 +346,7 @@ class PlayableVideo(components.Video):
visible=visible,
elem_id=elem_id,
mirror_webcam=mirror_webcam,
include_audio=include_audio,
**kwargs,
)

View File

@ -20,6 +20,7 @@
export let loading_status: LoadingStatus;
export let style: Styles = {};
export let mirror_webcam: boolean;
export let include_audio: boolean;
export let mode: "static" | "dynamic";
@ -60,6 +61,7 @@
or_text={$_("or")}
upload_text={$_("interface.click_to_upload")}
{mirror_webcam}
{include_audio}
on:change
on:clear
on:play

View File

@ -9,6 +9,7 @@
export let mode: "image" | "video" = "image";
export let mirror_webcam: boolean;
export let include_audio: boolean;
const dispatch = createEventDispatcher();
@ -17,9 +18,11 @@
async function access_webcam() {
try {
stream = await navigator.mediaDevices.getUserMedia({
video: true
video: true,
audio: include_audio
});
video_source.srcObject = stream;
video_source.muted = true;
video_source.play();
} catch (err) {
if (err instanceof DOMException && err.name == "NotAllowedError") {

View File

@ -14,6 +14,7 @@
export let label: string | undefined = undefined;
export let show_label: boolean;
export let mirror_webcam: boolean;
export let include_audio: boolean;
export let drop_text: string = "Drop a video file";
export let or_text: string = "or";
@ -63,6 +64,7 @@
{:else if source === "webcam"}
<Webcam
{mirror_webcam}
{include_audio}
mode="video"
on:error
on:capture={({ detail }) => dispatch("change", detail)}