Skip to content

Commit

Permalink
Remove HLS caption handling (#443)
Browse files Browse the repository at this point in the history
* Remove duplicated caption overlays in iPads

* Only use IIIF manifest captions, remove HLS caption filters

* Cleanup code

* Fix caption building for mobile devices
  • Loading branch information
Dananji authored Mar 14, 2024
1 parent a5d96c4 commit 370d656
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 69 deletions.
7 changes: 2 additions & 5 deletions src/components/MediaPlayer/MediaPlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ const MediaPlayer = ({ enableFileDownload = false, enablePIP = false }) => {
const [isMultiCanvased, setIsMultiCanvased] = React.useState(false);
const [lastCanvasIndex, setLastCanvasIndex] = React.useState(0);
const [isVideo, setIsVideo] = React.useState();
const [isStream, setIsStream] = React.useState();

const {
canvasIndex,
Expand Down Expand Up @@ -132,14 +131,12 @@ const MediaPlayer = ({ enableFileDownload = false, enablePIP = false }) => {
mediaType,
canvas,
error,
isHLS
} = getMediaInfo({
manifest,
canvasIndex: canvasId,
srcIndex,
});
setIsVideo(mediaType === 'video');
setIsStream(isHLS);
manifestDispatch({ canvasTargets, type: 'canvasTargets' });
manifestDispatch({
canvasDuration: canvas.duration,
Expand Down Expand Up @@ -343,9 +340,9 @@ const MediaPlayer = ({ enableFileDownload = false, enablePIP = false }) => {
sources: isMultiSource
? playerConfig.sources[srcIndex]
: playerConfig.sources,
// Enable native text track functionality in iPhones and iPads when not using HLS streams
// Enable native text track functionality in iPhones and iPads
html5: {
nativeTextTracks: IS_MOBILE && !isStream && !IS_ANDROID
nativeTextTracks: IS_MOBILE && !IS_ANDROID
},
// Setting this option helps to override VideoJS's default 'keydown' event handler, whenever
// the focus is on a native VideoJS control icon (e.g. play toggle).
Expand Down
56 changes: 47 additions & 9 deletions src/components/MediaPlayer/VideoJS/VideoJSPlayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,14 +276,28 @@ function VideoJSPlayer({
playerDispatch({ isEnded: false, type: 'setIsEnded' });

let textTracks = player.textTracks();
// Filter the duplicated tracks by HLS manifest, these doesn't have a src attribute
let duplicatedTracks = textTracks.tracks_.filter(rt => rt.src === undefined);
// Remove the duplicated tracks from the captions/subtitles menu
if (tracks.length != textTracks.length && duplicatedTracks?.length > 0) {
for (let i = 0; i < duplicatedTracks.length; i++) {
player.textTracks().removeTrack(duplicatedTracks[i]);
}
/*
Filter the text track Video.js adds with an empty label and language
when nativeTextTracks are enabled for iPhones and iPads.
Related links, Video.js => https://github.com/videojs/video.js/issues/2808 and
in Apple => https://developer.apple.com/library/archive/qa/qa1801/_index.html
*/
if (IS_MOBILE && !IS_ANDROID) {
textTracks.on('addtrack', () => {
for (let i = 0; i < textTracks.length; i++) {
if (textTracks[i].language === '' && textTracks[i].label === '') {
player.textTracks().removeTrack(textTracks[i]);
/*
Turn off the consecutive `textTrack.change` event,
which turns off default captions in the controls
*/
textTracks.off('change');
}
if (i == 0) { textTracks[i].mode = 'showing'; }
}
});
}

// Turn captions on indicator via CSS on first load, when captions are ON by default
player.textTracks().tracks_?.map((t) => {
if (t.mode == 'showing') {
Expand Down Expand Up @@ -627,6 +641,30 @@ function VideoJSPlayer({
} else {
videoClass = "video-js vjs-big-play-centered";
};
const buildTrack = (t, index) => {
if (index == 0) {
return (
<track
key={t.key}
src={t.src}
kind={t.kind}
label={t.label}
srcLang={t.srclang}
default
/>
);
} else {
return (
<track
key={t.key}
src={t.src}
kind={t.kind}
label={t.label}
srcLang={t.srclang}
/>
);
}
};

return (
<React.Fragment>
Expand All @@ -641,14 +679,14 @@ function VideoJSPlayer({
onTouchEnd={mobilePlayToggle}
>
{tracks?.length > 0 && (
tracks.map(t =>
tracks.map((t, index) =>
<track
key={t.key}
src={t.src}
kind={t.kind}
label={t.label}
srcLang={t.srclang}
default
default={index === 0 ? 'true' : 'false'}
/>
)
)}
Expand Down
11 changes: 1 addition & 10 deletions src/services/iiif-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export function getCanvasIndex(manifest, canvasId) {
* @param {Object} obj.manifest IIIF Manifest
* @param {Number} obj.canvasIndex Index of the current canvas in manifest
* @param {Number} obj.srcIndex Index of the resource in active canvas
* @returns {Object} { soures, tracks, targets, isMultiSource, error, canvas, mediaType, isHLs }
* @returns {Object} { soures, tracks, targets, isMultiSource, error, canvas, mediaType }
*/
export function getMediaInfo({ manifest, canvasIndex, srcIndex = 0 }) {
let canvas = [];
Expand Down Expand Up @@ -169,14 +169,6 @@ export function getMediaInfo({ manifest, canvasIndex, srcIndex = 0 }) {
// Set default src to auto
sources = setDefaultSrc(resources, isMultiSource, srcIndex);

/*
Identify the media is streaming or not by testing whether the src includes .m3u8
OR media format includes HLS mime types => application/x-mpegURL or vnd.apple.mpegURL
*/
const isHLS = sources
.map(s => (/m3u8/i).test(s.src) || (/(application\/x-mpegURL)|(vnd.apple.mpegURL)/i).test(s.type))
.every(f => f === true);

// Read supplementing resources fom annotations
const supplementingRes = readAnnotations({
manifest,
Expand Down Expand Up @@ -210,7 +202,6 @@ export function getMediaInfo({ manifest, canvasIndex, srcIndex = 0 }) {
...mediaInfo,
error: null,
mediaType,
isHLS,
};
}
} catch (error) {
Expand Down
44 changes: 0 additions & 44 deletions src/services/iiif-parser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,50 +176,6 @@ describe('iiif-parser', () => {
expect(sources[2].selected).toBeTruthy();
});

describe('identifies media as stream', () => {
it('with src ending .m3u8', () => {
const { isHLS } = iiifParser.getMediaInfo({
manifest: singleSrcManifest,
canvasIndex: 1,
});
expect(isHLS).toBeTruthy();
});

it('with src media fragment with .m3u8', () => {
const { isHLS } = iiifParser.getMediaInfo({
manifest: playlistManifest,
canvasIndex: 1,
});
expect(isHLS).toBeTruthy();
});

it('with media format as vnd.apple.mpegURL', () => {
const { isHLS } = iiifParser.getMediaInfo({
manifest: singleSrcManifest,
canvasIndex: 0,
});
expect(isHLS).toBeTruthy();
});
});

describe('identifies media as non-stream', () => {
it('with src ending .mp4', () => {
const { isHLS } = iiifParser.getMediaInfo({
manifest: lunchroomManifest,
canvasIndex: 0,
});
expect(isHLS).toBeFalsy();
});

it('with media fragment with .mp4', () => {
const { isHLS } = iiifParser.getMediaInfo({
manifest: playlistManifest,
canvasIndex: 2,
});
expect(isHLS).toBeFalsy();
});
});

it("selects the first source when quality 'auto' is not present", () => {
const { sources } = iiifParser.getMediaInfo({
manifest: lunchroomManifest,
Expand Down
2 changes: 1 addition & 1 deletion src/services/utility-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ function getResourceInfo(item, motivation) {
};
if (motivation === 'supplementing') {
// Set language for captions/subtitles
s.srclang = item.getProperty('language') || 'en';
s.srclang = item.getProperty('language') || 'eng';
// Specify kind to subtitles for VTT annotations. Without this VideoJS
// resolves the kind to metadata for subtitles file, resulting in empty
// subtitles lists in iOS devices' native palyers
Expand Down

0 comments on commit 370d656

Please sign in to comment.