mirror of https://github.com/OpenVidu/openvidu.git
openvidu-test-app: allow forcing encoder resolution change on a video publisher with LocalVideoTrack.restartTrack method
parent
adb21bc6c4
commit
ab3c341646
|
|
@ -56,18 +56,31 @@ video {
|
||||||
/* Keep the form-field visually compact (16×16 clipped box).
|
/* Keep the form-field visually compact (16×16 clipped box).
|
||||||
The CDK overlay uses the Popover API (top layer) so it is
|
The CDK overlay uses the Popover API (top layer) so it is
|
||||||
immune to overflow:hidden and renders at its natural size. */
|
immune to overflow:hidden and renders at its natural size. */
|
||||||
#max-video-quality {
|
#max-video-quality,
|
||||||
|
#restart-video-resolution {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
--mat-form-field-container-vertical-padding: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::ng-deep #max-video-quality .mdc-notched-outline * {
|
/* The MDC outlined text field reserves 16px of horizontal padding
|
||||||
|
for the value, which alone exceeds this 16px-wide box and pushes
|
||||||
|
the value/arrow trigger (and therefore the dropdown svg) out of
|
||||||
|
the visible area. Removing it keeps the trigger inside the clip. */
|
||||||
|
::ng-deep #max-video-quality .mat-mdc-text-field-wrapper,
|
||||||
|
::ng-deep #restart-video-resolution .mat-mdc-text-field-wrapper {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep #max-video-quality .mdc-notched-outline *,
|
||||||
|
::ng-deep #restart-video-resolution .mdc-notched-outline * {
|
||||||
border-color: transparent !important;
|
border-color: transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
::ng-deep #max-video-quality .mat-mdc-form-field-subscript-wrapper {
|
::ng-deep #max-video-quality .mat-mdc-form-field-subscript-wrapper,
|
||||||
|
::ng-deep #restart-video-resolution .mat-mdc-form-field-subscript-wrapper {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,20 +7,26 @@
|
||||||
<mat-icon aria-label="Mute/Unmute video" class="mat-icon material-icons" role="img"
|
<mat-icon aria-label="Mute/Unmute video" class="mat-icon material-icons" role="img"
|
||||||
aria-hidden="true">{{muteVideoIcon}}</mat-icon>
|
aria-hidden="true">{{muteVideoIcon}}</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
}
|
|
||||||
@if (localParticipant) {
|
|
||||||
<button (click)="unpublishTrack()" class="video-btn publish-unpublish-video" matTooltip="Unpublish track"
|
<button (click)="unpublishTrack()" class="video-btn publish-unpublish-video" matTooltip="Unpublish track"
|
||||||
matTooltipClass="custom-tooltip">
|
matTooltipClass="custom-tooltip">
|
||||||
<mat-icon aria-label="Unpublish track" class="mat-icon material-icons" role="img"
|
<mat-icon aria-label="Unpublish track" class="mat-icon material-icons" role="img"
|
||||||
aria-hidden="true">stop</mat-icon>
|
aria-hidden="true">stop</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
}
|
|
||||||
@if (localParticipant) {
|
|
||||||
<button (click)="openProcessorDialog()" class="video-btn toggle-track-processor" matTooltip="Open track processor settings"
|
<button (click)="openProcessorDialog()" class="video-btn toggle-track-processor" matTooltip="Open track processor settings"
|
||||||
matTooltipClass="custom-tooltip">
|
matTooltipClass="custom-tooltip">
|
||||||
<mat-icon aria-label="Open track processor settings" class="mat-icon material-icons" role="img"
|
<mat-icon aria-label="Open track processor settings" class="mat-icon material-icons" role="img"
|
||||||
aria-hidden="true">auto_fix_high</mat-icon>
|
aria-hidden="true">auto_fix_high</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<mat-form-field id="restart-video-resolution" class="video-btn quality-option" matTooltip="Restart video at resolution" matTooltipClass="custom-tooltip">
|
||||||
|
<mat-select [(value)]="restartResolution" (selectionChange)="onRestartResolutionChange()">
|
||||||
|
@for (r of ['1920x1080', '1280x720', '640x360', '320x180']; track r) {
|
||||||
|
<mat-option [value]="r" [ngClass]="'res-' + r">{{r}}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
}
|
}
|
||||||
@if (!localParticipant) {
|
@if (!localParticipant) {
|
||||||
<button (click)="toggleEnableTrack()" class="video-btn toggle-video-enabled" matTooltip="Toggle track enabled"
|
<button (click)="toggleEnableTrack()" class="video-btn toggle-video-enabled" matTooltip="Toggle track enabled"
|
||||||
|
|
@ -28,15 +34,13 @@
|
||||||
<mat-icon aria-label="Toggle track enabled" class="mat-icon material-icons" role="img"
|
<mat-icon aria-label="Toggle track enabled" class="mat-icon material-icons" role="img"
|
||||||
aria-hidden="true">{{trackEnabled ? 'toggle_off' : 'toggle_on'}}</mat-icon>
|
aria-hidden="true">{{trackEnabled ? 'toggle_off' : 'toggle_on'}}</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
}
|
|
||||||
@if (!localParticipant) {
|
|
||||||
<button (click)="toggleSubscribeTrack()" class="video-btn toggle-video-subscribed" matTooltip="Toggle track subscription"
|
<button (click)="toggleSubscribeTrack()" class="video-btn toggle-video-subscribed" matTooltip="Toggle track subscription"
|
||||||
matTooltipClass="custom-tooltip">
|
matTooltipClass="custom-tooltip">
|
||||||
<mat-icon aria-label="Toggle track subscription" class="mat-icon material-icons" role="img"
|
<mat-icon aria-label="Toggle track subscription" class="mat-icon material-icons" role="img"
|
||||||
aria-hidden="true">{{trackSubscribed ? 'stop' : 'play_arrow'}}</mat-icon>
|
aria-hidden="true">{{trackSubscribed ? 'stop' : 'play_arrow'}}</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
}
|
|
||||||
@if (!localParticipant) {
|
|
||||||
<mat-form-field id="max-video-quality" class="video-btn quality-option" matTooltip="Set video quality" matTooltipClass="custom-tooltip">
|
<mat-form-field id="max-video-quality" class="video-btn quality-option" matTooltip="Set video quality" matTooltipClass="custom-tooltip">
|
||||||
<mat-select [(value)]="maxVideoQuality" (selectionChange)="onQualityChange()">
|
<mat-select [(value)]="maxVideoQuality" (selectionChange)="onQualityChange()">
|
||||||
@for (q of ['LOW', 'MEDIUM', 'HIGH']; track q) {
|
@for (q of ['LOW', 'MEDIUM', 'HIGH']; track q) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { Component, inject, ChangeDetectionStrategy } from '@angular/core';
|
||||||
import { NgClass } from '@angular/common';
|
import { NgClass } from '@angular/common';
|
||||||
import {
|
import {
|
||||||
LocalTrack,
|
LocalTrack,
|
||||||
|
LocalVideoTrack,
|
||||||
VideoTrack,
|
VideoTrack,
|
||||||
RemoteTrackPublication,
|
RemoteTrackPublication,
|
||||||
VideoQuality,
|
VideoQuality,
|
||||||
|
|
@ -32,6 +33,8 @@ import { MatSelectModule } from '@angular/material/select';
|
||||||
export class VideoTrackComponent extends TrackComponent {
|
export class VideoTrackComponent extends TrackComponent {
|
||||||
muteVideoIcon: string = 'videocam';
|
muteVideoIcon: string = 'videocam';
|
||||||
maxVideoQuality: string;
|
maxVideoQuality: string;
|
||||||
|
// Resolution to re-capture the local video track at (see onRestartResolutionChange)
|
||||||
|
restartResolution: string;
|
||||||
|
|
||||||
videoZoom = false;
|
videoZoom = false;
|
||||||
|
|
||||||
|
|
@ -96,6 +99,16 @@ export class VideoTrackComponent extends TrackComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-captures the local video track at the selected resolution. Useful to make
|
||||||
|
// the encoder change its layer structure on the fly: an SVC encoder drops its
|
||||||
|
// upper spatial layers when the capture is too small to host them
|
||||||
|
async onRestartResolutionChange() {
|
||||||
|
const [width, height] = this.restartResolution.split('x').map(Number);
|
||||||
|
await (this._track as LocalVideoTrack).restartTrack({
|
||||||
|
resolution: { width, height, frameRate: 30 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
openInfoDialog() {
|
openInfoDialog() {
|
||||||
const updateFunction = async (): Promise<string> => {
|
const updateFunction = async (): Promise<string> => {
|
||||||
const videoLayers: any[] = [];
|
const videoLayers: any[] = [];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue