mirror of
https://github.com/gradio-app/gradio.git
synced 2024-11-27 01:40:20 +08:00
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:
parent
066adf1a9d
commit
24f413c4b3
@ -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)!
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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,
|
||||
)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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") {
|
||||
|
@ -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)}
|
||||
|
Loading…
Reference in New Issue
Block a user