增加画中画模式

This commit is contained in:
杍超
2025-01-22 19:12:30 +08:00
parent 4b5968acd4
commit 053b365b7b
4 changed files with 39 additions and 17 deletions

View File

@@ -703,7 +703,7 @@ class WebRTC(Component):
time_limit: float | None = None, time_limit: float | None = None,
mode: Literal["send-receive", "receive", "send"] = "send-receive", mode: Literal["send-receive", "receive", "send"] = "send-receive",
modality: Literal["video", "audio", "audio-video"] = "video", modality: Literal["video", "audio", "audio-video"] = "video",
show_local_video: bool = True, # TODO 先默认打开 show_local_video: Literal['picture-in-picture', 'left-right', None] = None,
rtp_params: dict[str, Any] | None = None, rtp_params: dict[str, Any] | None = None,
icon: str | None = None, icon: str | None = None,
icon_button_color: str | None = None, icon_button_color: str | None = None,
@@ -735,7 +735,7 @@ class WebRTC(Component):
time_limit: Maximum duration in seconds for recording. time_limit: Maximum duration in seconds for recording.
mode: WebRTC mode - "send-receive", "receive", or "send". mode: WebRTC mode - "send-receive", "receive", or "send".
modality: Type of media - "video" or "audio". modality: Type of media - "video" or "audio".
show_local_video: in send-receive mode and audio-video modality, whether to show the local video stream. show_local_video: in send-receive mode and audio-video modality, whether to show the local video stream. - "picture-in-picture" or "left-right".
rtp_params: See https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/setParameters. If you are changing the video resolution, you can set this to {"degradationPreference": "maintain-framerate"} to keep the frame rate consistent. rtp_params: See https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/setParameters. If you are changing the video resolution, you can set this to {"degradationPreference": "maintain-framerate"} to keep the frame rate consistent.
icon: Icon to display on the button instead of the wave animation. The icon should be a path/url to a .svg/.png/.jpeg file. icon: Icon to display on the button instead of the wave animation. The icon should be a path/url to a .svg/.png/.jpeg file.
icon_button_color: Color of the icon button. Default is var(--color-accent) of the demo theme. icon_button_color: Color of the icon button. Default is var(--color-accent) of the demo theme.

View File

@@ -95,12 +95,12 @@ with gr.Blocks(css=css) as demo:
with gr.Column(): with gr.Column():
webrtc = WebRTC( webrtc = WebRTC(
width=1500, width=500,
height=500, height=1500,
label="Local", label="Video Chat",
modality="audio-video", modality="audio-video",
mode="send-receive", mode="send-receive",
show_local_video=True, show_local_video='picture-in-picture',
elem_id="video-source", elem_id="video-source",
) )
webrtc.stream( webrtc.stream(

Binary file not shown.

View File

@@ -62,7 +62,7 @@
}; };
export let include_audio: boolean; export let include_audio: boolean;
export let show_local_video: boolean; export let show_local_video: string;
export let i18n: I18nFormatter; export let i18n: I18nFormatter;
let volumeMuted = false let volumeMuted = false
@@ -258,20 +258,23 @@
<!-- svelte-ignore a11y-media-has-caption --> <!-- svelte-ignore a11y-media-has-caption -->
<!-- need to suppress for video streaming https://github.com/sveltejs/svelte/issues/5967 --> <!-- need to suppress for video streaming https://github.com/sveltejs/svelte/issues/5967 -->
{#if show_local_video} {#if show_local_video}
<div class="video-wrap"> <div class="video-wrap" class:picinpic={show_local_video === 'picture-in-picture'} class:left-right={show_local_video === 'left-right'} class:hide={!webcam_accessed}>
<video <video
class="local-video"
bind:this={local_video_source} bind:this={local_video_source}
class:hide={!webcam_accessed} class:hide={!webcam_accessed}
autoplay={true} autoplay={true}
playsinline={true} playsinline={true}
muted
/> />
<video <video
class="remote-video"
bind:this={video_source} bind:this={video_source}
class:hide={!webcam_received} class:hide={!webcam_received}
class:flip={stream_state != "open" || class:flip={stream_state != "open" ||
(stream_state === "open" && include_audio)} (stream_state === "open" && include_audio)}
autoplay={true} autoplay={true}
muted={volumeMuted} muted={volumeMuted}
playsinline={true} playsinline={true}
/> />
</div> </div>
@@ -431,30 +434,49 @@
height: var(--size-full); height: var(--size-full);
} }
.video-wrap {
height: 100%;
width: 100%;
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.hide { .hide {
display: none; display: none;
} }
.video-wrap {
display: flex;
justify-content: center;
align-items: center;
}
video { video {
width: var(--size-full); width: var(--size-full);
height: var(--size-full); height: var(--size-full);
object-fit: cover; object-fit: cover;
} }
.video-wrap video { .video-wrap.left-right video {
width: calc(50% - 3px); width: calc(50% - 3px);
height: 50%; height: 50%;
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
} }
.video-wrap video:last-child { .video-wrap.left-right video:last-child {
margin-left: 6px; margin-left: 6px;
} }
.video-wrap.picinpic .remote-video {
width: var(--size-full);
height: var(--size-full);
object-fit: contain;
}
.video-wrap.picinpic .local-video {
position:absolute;
left: 5%;
bottom: 15%;
/* width: 20%; */
object-fit: contain;
object-position: left;
height: 20%;
z-index: 1;
}
.button-wrap { .button-wrap {
position: absolute; position: absolute;