Skip to content
Merged
2 changes: 2 additions & 0 deletions examples/nextjs-with-typescript/pages/MuxPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ function MuxPlayerPage({ location }: Props) {
// startLevel: 2,
// debug: true,
// }}
preferLowerResolution={false}
capDefaultResolution={700}
title={state.title}
videoTitle={state.videoTitle}
startTime={state.startTime}
Expand Down
2 changes: 2 additions & 0 deletions examples/nextjs-with-typescript/pages/mux-player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ function MuxPlayerWCPage() {
playback-id={playbackId}
forward-seek-offset={10}
backward-seek-offset={10}
//prefer-lower-resolution={false}
cap-default-resolution={550}
// onPlayerReady={() => console.log("ready!")}
{...debugObj}
{...mutedObj}
Expand Down
2 changes: 2 additions & 0 deletions packages/mux-player-react/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
| `preferPlayback` | `"mse" \| "native"` | Specify if Mux Player should try to use Media Source Extension or native playback (if available). If no value is provided, Mux Player will choose based on what's deemed optimal for content and playback environment. | Varies |
| `maxResolution` | `"720p" \| "1080p" \| "1440p" \| "2160p"` | Specify the maximum resolution you want delivered for this video. | N/A |
| `minResolution` | `"480p" \| "540p" \| "720p" \| "1080p" \| "1440p" \| "2160p"` | Specify the minimum resolution you want delivered for this video. | N/A |
| `capDefaultResolution` | `number` (dimension in pixels, e.g. `540` for 540p) | Cap the default resolution selection to the specified dimension in pixels. For landscape videos, the height is capped. For portrait videos, the width is capped. For example, setting `540` will cap landscape videos at 540p height and portrait videos at 540px width. When combined with `preferLowerResolution`, controls which resolution is selected when there's no exact match. If there's an exact match for the cap value, it will be used regardless of `preferLowerResolution`. | N/A |
| `preferLowerResolution` | `boolean` | When `capDefaultResolution` is set and there's no exact match, controls resolution selection: `false` (default) selects the lowest resolution that exceeds the cap, `true` selects the highest resolution that doesn't exceed the cap. | `false` |
| `renditionOrder` | `"desc"` | Change the order in which renditions are provided in the src playlist. Can impact initial segment loads. Currently only support `"desc"` for descending order | N/A |
| `programStartTime` | `number` | Apply PDT-based [instant clips](https://docs.mux.com/guides/create-instant-clips) to the beginning of the media stream. | N/A |
| `programEndTime` | `number` | Apply PDT-based [instant clips](https://docs.mux.com/guides/create-instant-clips) to the end of the media stream. | N/A |
Expand Down
2 changes: 2 additions & 0 deletions packages/mux-player-react/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export type MuxPlayerProps = {
backwardSeekOffset?: number;
maxResolution?: MaxResolutionValue;
minResolution?: MinResolutionValue;
preferLowerResolution?: boolean;
capDefaultResolution?: number;
renditionOrder?: RenditionOrderValue;
programStartTime?: number;
programEndTime?: number;
Expand Down
2 changes: 2 additions & 0 deletions packages/mux-player/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
| `prefer-playback` | `"mse" \| "native"` | Specify if Mux Player should try to use Media Source Extension or native playback (if available). If no value is provided, Mux Player will choose based on what's deemed optimal for content and playback environment. | Varies |
| `max-resolution` | `"720p" \| "1080p" \| "1440p" \| "2160p"` | Specify the maximum resolution you want delivered for this video. | N/A |
| `min-resolution` | `"480p" \| "540p" \| "720p" \| "1080p" \| "1440p" \| "2160p"` | Specify the minimum resolution you want delivered for this video. | N/A |
| `cap-default-resolution` | `number` (dimension in pixels, e.g. `540` for 540p) | Cap the default resolution selection to the specified dimension in pixels. For landscape videos, the height is capped. For portrait videos, the width is capped. For example, setting `540` will cap landscape videos at 540p height and portrait videos at 540px width. When combined with `prefer-lower-resolution`, controls which resolution is selected when there's no exact match. If there's an exact match for the cap value, it will be used regardless of `prefer-lower-resolution`. | N/A |
| `prefer-lower-resolution` | `boolean` | When `cap-default-resolution` is set and there's no exact match, controls resolution selection: `false` (default) selects the lowest resolution that exceeds the cap, `true` selects the highest resolution that doesn't exceed the cap. | `false` |
| `rendition-order` | `"desc"` | Change the order in which renditions are provided in the src playlist. Can impact initial segment loads. Currently only support `"desc"` for descending order | N/A |
| `program-start-time` | `number` | Apply PDT-based [instant clips](https://docs.mux.com/guides/create-instant-clips) to the beginning of the media stream. | N/A |
| `program-end-time` | `number` | Apply PDT-based [instant clips](https://docs.mux.com/guides/create-instant-clips) to the end of the media stream. | N/A |
Expand Down
33 changes: 33 additions & 0 deletions packages/mux-player/src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ function getProps(el: MuxPlayerElement, state?: any): MuxTemplateProps {
beaconCollectionDomain: el.beaconCollectionDomain,
maxResolution: el.maxResolution,
minResolution: el.minResolution,
preferLowerResolution: el.preferLowerResolution,
capDefaultResolution: el.capDefaultResolution,
programStartTime: el.programStartTime,
programEndTime: el.programEndTime,
assetStartTime: el.assetStartTime,
Expand Down Expand Up @@ -1347,6 +1349,37 @@ class MuxPlayerElement extends VideoApiElement implements IMuxPlayerElement {
}
}

get preferLowerResolution() {
const attr = this.getAttribute(MuxVideoAttributes.PREFER_LOWER_RESOLUTION);
if (attr === null) {
return false;
}

return attr !== 'false';
}

set preferLowerResolution(val: boolean | undefined) {
if (val === this.preferLowerResolution) return;

if (val) {
this.setAttribute(MuxVideoAttributes.PREFER_LOWER_RESOLUTION, '');
} else {
this.removeAttribute(MuxVideoAttributes.PREFER_LOWER_RESOLUTION);
}
}

get capDefaultResolution() {
return toNumberOrUndefined(this.getAttribute(MuxVideoAttributes.CAP_DEFAULT_RESOLUTION));
}

set capDefaultResolution(val: number | undefined) {
if (val == undefined) {
this.removeAttribute(MuxVideoAttributes.CAP_DEFAULT_RESOLUTION);
} else {
this.setAttribute(MuxVideoAttributes.CAP_DEFAULT_RESOLUTION, `${val}`);
}
}

get renditionOrder() {
return (this.getAttribute(MuxVideoAttributes.RENDITION_ORDER) as RenditionOrderValue) ?? undefined;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/mux-player/src/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ export const content = (props: MuxTemplateProps) => html`
drm-token="${props.tokens?.drm ?? false}"
exportparts="video"
disable-pseudo-ended="${props.disablePseudoEnded ?? false}"
prefer-lower-resolution="${props.preferLowerResolution ?? false}"
cap-default-resolution="${props.capDefaultResolution ?? false}"
>
${props.storyboard
? html`<track label="thumbnails" default kind="metadata" src="${props.storyboard}" />`
Expand Down
2 changes: 2 additions & 0 deletions packages/mux-player/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export type MuxTemplateProps = Partial<MuxPlayerProps> & {
inLiveWindow: boolean;
maxResolution?: MaxResolutionValue;
minResolution?: MinResolutionValue;
preferLowerResolution?: boolean;
capDefaultResolution?: number;
renditionOrder?: RenditionOrderValue;
extraSourceParams?: Record<string, any>;
tokens: {
Expand Down
2 changes: 2 additions & 0 deletions packages/mux-video/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ Now you are free to use this web component in your HTML, just as you would with

- `max-resolution`: This can be used to cap or expand the maximum resolution of the video delivered. When using signed URLs this attribute will not work and instead you will need to include the `max_resolution` parameter in your signed token.
- `min-resolution`: This can be used to to cap or expand the minimum resolution of the video delivered. When using signed URLs this attribute will not work and instead you will need to include the `min_resolution` parameter in your signed token.
- `cap-default-resolution`: Cap the default resolution selection to the specified dimension in pixels (e.g. `540` for 540p). For landscape videos, the height is capped. For portrait videos, the width is capped. For example, setting `540` will cap landscape videos at 540p height and portrait videos at 540px width. When combined with `prefer-lower-resolution`, controls which resolution is selected when there's no exact match. If there's an exact match for the cap value, it will be used regardless of `prefer-lower-resolution`.
- `prefer-lower-resolution`: When `cap-default-resolution` is set and there's no exact match, controls resolution selection: `false` (default) selects the lowest resolution that exceeds the cap, `true` selects the highest resolution that doesn't exceed the cap.
- `rendition-order`: Set to `"desc"` to make the renditions of the video delivered be sorted in descending resolution order, which can impact the initial resolution loaded. When using signed URLs this attribute will not work and instead you will need to include the `rendition_order` parameter in your signed token.
- `program-start-time`: Apply PDT-based [instant clips](https://docs.mux.com/guides/create-instant-clips) to the beginning of the media stream.
- `program-end-time`: Apply PDT-based [instant clips](https://docs.mux.com/guides/create-instant-clips) to the end of the media stream.
Expand Down
36 changes: 36 additions & 0 deletions packages/mux-video/src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ export const Attributes = {
ENV_KEY: 'env-key',
MAX_RESOLUTION: 'max-resolution',
MIN_RESOLUTION: 'min-resolution',
PREFER_LOWER_RESOLUTION: 'prefer-lower-resolution',
CAP_DEFAULT_RESOLUTION: 'cap-default-resolution',
RENDITION_ORDER: 'rendition-order',
PROGRAM_START_TIME: 'program-start-time',
PROGRAM_END_TIME: 'program-end-time',
Expand Down Expand Up @@ -413,6 +415,40 @@ export class MuxVideoBaseElement extends CustomVideoElement implements IMuxVideo
}
}

get preferLowerResolution() {
const attr = this.getAttribute(Attributes.PREFER_LOWER_RESOLUTION);
if (attr === null) {
return false;
}

return attr !== 'false';
}

set preferLowerResolution(val: boolean | undefined) {
if (val === this.preferLowerResolution) return;

if (val) {
this.setAttribute(Attributes.PREFER_LOWER_RESOLUTION, '');
} else {
this.removeAttribute(Attributes.PREFER_LOWER_RESOLUTION);
}
}

get capDefaultResolution() {
const value = this.getAttribute(Attributes.CAP_DEFAULT_RESOLUTION);
if (value === null) return undefined;
const num = parseInt(value, 10);
return isNaN(num) ? undefined : num;
}

set capDefaultResolution(val: number | undefined) {
if (val == undefined) {
this.removeAttribute(Attributes.CAP_DEFAULT_RESOLUTION);
} else {
this.setAttribute(Attributes.CAP_DEFAULT_RESOLUTION, `${val}`);
}
}

get renditionOrder() {
return (this.getAttribute(Attributes.RENDITION_ORDER) as RenditionOrderValue) ?? undefined;
}
Expand Down
32 changes: 30 additions & 2 deletions packages/playback-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -695,12 +695,31 @@ export const setupHls = (
props: Partial<
Pick<
MuxMediaPropsInternal,
'debug' | 'streamType' | 'type' | 'startTime' | 'metadata' | 'preferCmcd' | '_hlsConfig' | 'tokens' | 'drmTypeCb'
| 'debug'
| 'streamType'
| 'type'
| 'startTime'
| 'metadata'
| 'preferCmcd'
| '_hlsConfig'
| 'tokens'
| 'drmTypeCb'
| 'preferLowerResolution'
| 'capDefaultResolution'
>
>,
mediaEl: HTMLMediaElement
) => {
const { debug, streamType, startTime: startPosition = -1, metadata, preferCmcd, _hlsConfig = {} } = props;
const {
debug,
streamType,
startTime: startPosition = -1,
metadata,
preferCmcd,
_hlsConfig = {},
preferLowerResolution,
capDefaultResolution,
} = props;
const type = getType(props);
const hlsType = type === ExtensionMimeTypeMap.M3U8;
const shouldUseNative = useNative(props, mediaEl);
Expand Down Expand Up @@ -753,6 +772,15 @@ export const setupHls = (
..._hlsConfig,
}) as HlsInterface;

if (capLevelControllerObj.capLevelController === MinCapLevelController) {
if (preferLowerResolution !== undefined) {
MinCapLevelController.setPreferLowerResolution(hls, preferLowerResolution);
}
if (capDefaultResolution !== undefined) {
MinCapLevelController.setCapDefaultResolution(hls, capDefaultResolution);
}
}

hls.on(Hls.Events.MANIFEST_PARSED, async function (_event, data) {
const chapters = data.sessionData?.['com.apple.hls.chapters'];
if (chapters?.URI || chapters?.VALUE.toLocaleLowerCase().startsWith('http')) {
Expand Down
Loading
Loading