Skip to content

Commit

Permalink
Merge pull request #6224 from mozilla/CleanupMediaVideoImageLoaderData
Browse files Browse the repository at this point in the history
bitECS: Clean up MediaImage/VideoLoaderData
  • Loading branch information
takahirox authored Sep 13, 2023
2 parents 0febf15 + f38b6ca commit ebabfdf
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 90 deletions.
33 changes: 25 additions & 8 deletions src/bit-components.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,31 @@ export const MediaContentBounds = defineComponent({
bounds: [Types.f32, 3]
});

// MediaImageLoaderData and MediaVideoLoaderData are
// for parameters that are set at glTF inflators
// inflateImageLoader and inflateVideoLoader and
// are needed to be transported to util image/audio loaders.
// They are handled as part of MediaLoader component data.

/**
* @type {Map<EntityId, {
* alphaCutoff: number,
* alphaMode: AlphaMode,
* projection: ProjectionMode
* }>}
*/
export const MediaImageLoaderData = new Map();

/**
* @type {Map<EntityId, {
* loop: boolean,
* autoPlay: boolean,
* controls: boolean,
* projection: ProjectionMode
* }>}
*/
export const MediaVideoLoaderData = new Map();

export const SceneRoot = defineComponent();
export const NavMesh = defineComponent();
export const SceneLoader = defineComponent({ src: Types.ui32 });
Expand All @@ -174,10 +199,6 @@ export const MediaImage = defineComponent({
alphaCutoff: Types.f32
});
MediaImage.cacheKey[$isStringType] = true;
/**
* @type {Map<EntityId, ImageLoaderParams}>}
*/
export const MediaImageLoaderData = new Map();

export const NetworkedPDF = defineComponent({
pageNumber: Types.ui8
Expand All @@ -192,10 +213,6 @@ export const MediaVideo = defineComponent({
flags: Types.ui8,
projection: Types.ui8
});
/**
* @type {Map<EntityId, VideoLoaderParams}>}
*/
export const MediaVideoLoaderData = new Map();
/**
* @type {Map<EntityId, HTMLVideoElement}>}
*/
Expand Down
90 changes: 57 additions & 33 deletions src/bit-systems/media-loading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import {
GLTFModel,
LoadedByMediaLoader,
MediaContentBounds,
MediaImageLoaderData,
MediaLoaded,
MediaLoader,
MediaVideoLoaderData,
Networked,
ObjectMenuTarget
} from "../bit-components";
Expand Down Expand Up @@ -66,34 +68,6 @@ export function* waitForMediaLoaded(world: HubsWorld, eid: EntityID) {
}
}

// prettier-ignore
const loaderForMediaType = {
[MediaType.IMAGE]: (
world: HubsWorld,
eid: EntityID,
{ accessibleUrl, contentType }: { accessibleUrl: string, contentType: string }
) => loadImage(world, eid, accessibleUrl, contentType),
[MediaType.VIDEO]: (
world: HubsWorld,
eid: EntityID,
{ accessibleUrl, contentType }: { accessibleUrl: string, contentType: string }
) => loadVideo(world, eid, accessibleUrl, contentType),
[MediaType.MODEL]: (
world: HubsWorld,
eid: EntityID,
{ accessibleUrl, contentType }: { accessibleUrl: string, contentType: string }
) => loadModel(world, accessibleUrl, contentType, true),
[MediaType.PDF]: (world: HubsWorld, eid: EntityID, { accessibleUrl }: { accessibleUrl: string }) =>
loadPDF(world, accessibleUrl),
[MediaType.AUDIO]: (world: HubsWorld, eid: EntityID, { accessibleUrl }: { accessibleUrl: string }) =>
loadAudio(world, eid, accessibleUrl),
[MediaType.HTML]: (
world: HubsWorld,
eid: EntityID,
{ canonicalUrl, thumbnail }: { canonicalUrl: string, thumbnail: string }
) => loadHtml(world, canonicalUrl, thumbnail)
};

export const MEDIA_LOADER_FLAGS = {
RECENTER: 1 << 0,
RESIZE: 1 << 1,
Expand Down Expand Up @@ -190,6 +164,52 @@ type MediaInfo = {
thumbnail: string;
};

function* loadByMediaType(
world: HubsWorld,
eid: EntityID,
{ accessibleUrl, canonicalUrl, contentType, mediaType, thumbnail }: MediaInfo
) {
// Note: For Image, Video, and Audio, additional parameters can be
// set via glTF image/video/audio inflators inflateImageLoader
// and inflateVideoLoader.
// TODO: Refactor media loading flow to simplify.
// Only in loading glTF Image, Video, and Audio flows,
// specified parameters assignment is needed after loading
// content then using MediaImage/VideoLoaderData as like
// transporting data from the inflators. This may be like
// special and a bit less maintainable.
switch (mediaType) {
case MediaType.IMAGE:
return yield* loadImage(
world,
accessibleUrl,
contentType,
MediaImageLoaderData.has(eid) ? MediaImageLoaderData.get(eid)! : {}
);
case MediaType.VIDEO:
return yield* loadVideo(
world,
accessibleUrl,
contentType,
MediaVideoLoaderData.has(eid) ? MediaVideoLoaderData.get(eid)! : {}
);
case MediaType.MODEL:
return yield* loadModel(world, accessibleUrl, contentType, true);
case MediaType.PDF:
return yield* loadPDF(world, accessibleUrl);
case MediaType.AUDIO:
return yield* loadAudio(
world,
accessibleUrl,
MediaVideoLoaderData.has(eid) ? MediaVideoLoaderData.get(eid)! : {}
);
case MediaType.HTML:
return yield* loadHtml(world, canonicalUrl, thumbnail);
default:
throw new UnsupportedMediaTypeError(eid, mediaType);
}
}

function* loadMedia(world: HubsWorld, eid: EntityID) {
let loadingObjEid = 0;
const addLoadingObjectTimeout = crTimeout(() => {
Expand All @@ -201,11 +221,7 @@ function* loadMedia(world: HubsWorld, eid: EntityID) {
let media: EntityID;
try {
const urlData = (yield resolveMediaInfo(src)) as MediaInfo;
const loader = urlData.mediaType && loaderForMediaType[urlData.mediaType];
if (!loader) {
throw new UnsupportedMediaTypeError(eid, urlData.mediaType);
}
media = yield* loader(world, eid, urlData);
media = yield* loadByMediaType(world, eid, urlData);
addComponent(world, MediaLoaded, media);
} catch (e) {
console.error(e);
Expand Down Expand Up @@ -259,6 +275,14 @@ export function mediaLoadingSystem(world: HubsWorld) {

mediaLoaderExitQuery(world).forEach(function (eid) {
jobs.stop(eid);

if (MediaImageLoaderData.has(eid)) {
MediaImageLoaderData.delete(eid);
}

if (MediaVideoLoaderData.has(eid)) {
MediaVideoLoaderData.delete(eid);
}
});

jobs.tick();
Expand Down
15 changes: 11 additions & 4 deletions src/inflators/image-loader.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { HubsWorld } from "../app";
import { ProjectionModeName } from "../utils/projection-mode";
import { inflateMediaLoader } from "./media-loader";
import { MediaImageLoaderData } from "../bit-components";
import { AlphaModeName } from "../utils/create-image-mesh";
import { AlphaModeName, getAlphaModeFromAlphaModeName } from "../utils/create-image-mesh";
import { ProjectionModeName, getProjectionFromProjectionName } from "../utils/projection-mode";
import { inflateMediaLoader } from "./media-loader";

export interface ImageLoaderParams {
src: string;
Expand All @@ -27,5 +27,12 @@ export function inflateImageLoader(world: HubsWorld, eid: number, params: ImageL
});

const requiredParams = Object.assign({}, DEFAULTS, params) as Required<ImageLoaderParams>;
MediaImageLoaderData.set(eid, requiredParams);
MediaImageLoaderData.set(eid, {
alphaCutoff: requiredParams.alphaCutoff,
// This inflator is glTF inflator. alphaMode and projection are
// passed as strings from glTF. They are different typed, just regular enum,
// in Hubs Client internal. So needs to convert here.
alphaMode: getAlphaModeFromAlphaModeName(requiredParams.alphaMode),
projection: getProjectionFromProjectionName(requiredParams.projection)
});
}
12 changes: 10 additions & 2 deletions src/inflators/video-loader.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HubsWorld } from "../app";
import { MediaVideoLoaderData } from "../bit-components";
import { ProjectionModeName } from "../utils/projection-mode";
import { ProjectionModeName, getProjectionFromProjectionName } from "../utils/projection-mode";
import { inflateMediaLoader } from "./media-loader";

export interface VideoLoaderParams {
Expand Down Expand Up @@ -28,5 +28,13 @@ export function inflateVideoLoader(world: HubsWorld, eid: number, params: VideoL
});

const requiredParams = Object.assign({}, DEFAULTS, params) as Required<VideoLoaderParams>;
MediaVideoLoaderData.set(eid, requiredParams);
MediaVideoLoaderData.set(eid, {
autoPlay: requiredParams.autoPlay,
controls: requiredParams.controls,
// This inflator is glTF inflator. projection is passed as strings
// from glTF. It is different typed, just regular enum, in Hubs Client
// internal. So needs to convert here.
projection: getProjectionFromProjectionName(requiredParams.projection),
loop: requiredParams.loop
});
}
30 changes: 15 additions & 15 deletions src/utils/load-audio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ import { renderAsEntity } from "../utils/jsx-entity";
import { loadAudioTexture } from "../utils/load-audio-texture";
import { HubsWorld } from "../app";
import { HubsVideoTexture } from "../textures/HubsVideoTexture";
import { EntityID } from "./networking-types";
import { MediaVideoLoaderData } from "../bit-components";
import { VideoLoaderParams } from "../inflators/video-loader";

export function* loadAudio(world: HubsWorld, eid: EntityID, url: string) {
let loop = true;
let autoPlay = true;
let controls = true;
let projection = ProjectionMode.FLAT;
if (MediaVideoLoaderData.has(eid)) {
const params = MediaVideoLoaderData.get(eid)! as VideoLoaderParams;
loop = params.loop;
autoPlay = params.autoPlay;
controls = params.controls;
MediaVideoLoaderData.delete(eid);
}
type Params = {
loop?: boolean;
autoPlay?: boolean;
controls?: boolean;
projection?: ProjectionMode;
};

const DEFAULTS: Required<Params> = {
loop: true,
autoPlay: true,
controls: true,
projection: ProjectionMode.FLAT
};

export function* loadAudio(world: HubsWorld, url: string, params: Params) {
const { loop, autoPlay, controls, projection } = Object.assign({}, DEFAULTS, params);
const { texture, ratio, video }: { texture: HubsVideoTexture; ratio: number; video: HTMLVideoElement } =
yield loadAudioTexture(url, loop, autoPlay);

Expand Down
32 changes: 21 additions & 11 deletions src/utils/load-image.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
/** @jsx createElementEntity */
import { createElementEntity } from "../utils/jsx-entity";
import { ProjectionMode, getProjectionFromProjectionName } from "./projection-mode";
import { ProjectionMode } from "./projection-mode";
import { loadTextureCancellable } from "../utils/load-texture";
import { renderAsEntity } from "../utils/jsx-entity";
import { HubsWorld } from "../app";
import { Texture } from "three";
import { AlphaMode, getAlphaModeFromAlphaModeName } from "./create-image-mesh";
import { EntityID } from "./networking-types";
import { MediaImageLoaderData } from "../bit-components";
import { AlphaMode } from "./create-image-mesh";
import { ImageParams } from "../inflators/image";

export function* createImageDef(world: HubsWorld, url: string, contentType: string): Generator<any, ImageParams, any> {
Expand All @@ -34,15 +32,27 @@ export function* createImageDef(world: HubsWorld, url: string, contentType: stri
};
}

export function* loadImage(world: HubsWorld, eid: EntityID, url: string, contentType: string) {
type Params = {
alphaCutoff?: number;
alphaMode?: AlphaMode;
projection?: ProjectionMode;
};

export function* loadImage(world: HubsWorld, url: string, contentType: string, params: Params) {
const { alphaCutoff, alphaMode, projection } = params;

const imageDef = yield* createImageDef(world, url, contentType);

if (MediaImageLoaderData.has(eid)) {
const params = MediaImageLoaderData.get(eid)!;
imageDef.projection = getProjectionFromProjectionName(params.projection);
imageDef.alphaMode = getAlphaModeFromAlphaModeName(params.alphaMode);
imageDef.alphaCutoff = params.alphaCutoff;
MediaImageLoaderData.delete(eid);
if (alphaCutoff !== undefined) {
imageDef.alphaCutoff = alphaCutoff;
}

if (alphaMode !== undefined) {
imageDef.alphaMode = alphaMode;
}

if (projection !== undefined) {
imageDef.projection = projection;
}

return renderAsEntity(world, <entity name="Image" image={imageDef} />);
Expand Down
33 changes: 16 additions & 17 deletions src/utils/load-video.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
/** @jsx createElementEntity */
import { createElementEntity } from "../utils/jsx-entity";
import { ProjectionMode, getProjectionFromProjectionName } from "./projection-mode";
import { ProjectionMode } from "./projection-mode";
import { renderAsEntity } from "../utils/jsx-entity";
import { loadVideoTexture } from "../utils/load-video-texture";
import { HubsWorld } from "../app";
import { HubsVideoTexture } from "../textures/HubsVideoTexture";
import { EntityID } from "./networking-types";
import { MediaVideoLoaderData } from "../bit-components";
import { VideoLoaderParams } from "../inflators/video-loader";

export function* loadVideo(world: HubsWorld, eid: EntityID, url: string, contentType: string) {
let loop = true;
let autoPlay = true;
let controls = true;
let projection = ProjectionMode.FLAT;
if (MediaVideoLoaderData.has(eid)) {
const params = MediaVideoLoaderData.get(eid)! as VideoLoaderParams;
loop = params.loop;
autoPlay = params.autoPlay;
controls = params.controls;
projection = getProjectionFromProjectionName(params.projection);
MediaVideoLoaderData.delete(eid);
}
type Params = {
loop?: boolean;
autoPlay?: boolean;
controls?: boolean;
projection?: ProjectionMode;
};

const DEFAULTS: Required<Params> = {
loop: true,
autoPlay: true,
controls: true,
projection: ProjectionMode.FLAT
};

export function* loadVideo(world: HubsWorld, url: string, contentType: string, params: Params) {
const { loop, autoPlay, controls, projection } = Object.assign({}, DEFAULTS, params);
const { texture, ratio, video }: { texture: HubsVideoTexture; ratio: number; video: HTMLVideoElement } =
yield loadVideoTexture(url, contentType, loop, autoPlay);

Expand Down

0 comments on commit ebabfdf

Please sign in to comment.