Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subtitles never loaded with Firefox #490

Closed
belgattitude opened this issue Oct 1, 2018 · 7 comments
Closed

Subtitles never loaded with Firefox #490

belgattitude opened this issue Oct 1, 2018 · 7 comments

Comments

@belgattitude
Copy link
Contributor

dear @cookpete

Spent few hours trying to debug why firefox does not display (load) my subtitles, while chrome was doing it right.I would be grateful if you could confirm or help.

Here's an example:

https://soluble.io/react-player/demo-bugtracks/

The first video is rendered through <ReactPlayer>, the second with the native <video> tag. Both are set up to display subtitles. In firefox you'll see the <ReactPlayer> version does not show anything.

(code is available: https://github.com/belgattitude/react-player/blob/demo/bug-tracks-firefox/src/demo/App.js#L112 on my branch)

I've been thinking about a firefox bug, but I'm not sure.. so I wrote a basic video player and it worked quite well:

https://gist.github.com/belgattitude/26d00cbd33df56567845b5a76f265a0b

Can you help ?

@belgattitude
Copy link
Contributor Author

belgattitude commented Oct 1, 2018

FYI, I think the issue is with how react add/remove text tracks... In a prototype I've been able to fix the issue by managing tracks through the dom:

If you look to the code below, you'll see that I'm not relying on render method to add tracks, but do the job in onLoadedMetadata:

    onLoadedMetadata = (e: SyntheticEvent<HTMLVideoElement>) => {
        const video = e.currentTarget;

        // As a workaround for Firefox, let's remove old tracks
        // before adding the new ones. Letting react do
        // the job does not seems to work properly
        const oldTracks = video.querySelectorAll('track');
        oldTracks.forEach((oldTrack) => {
            video.removeChild(oldTrack);
        });

        if (this.props.tracks) {
            this.props.tracks.map((t, trackIdx) => {
                const track = document.createElement('track');
                track.kind = t.kind!;
                track.label = t.label!;
                track.srclang = t.srcLang!;
                track.default = t.default!;
                track.src = t.src!;
                track.addEventListener('error', (e: Event) => {
                    console.warn(`Cannot load track ${t.src!}`)
                });
                track.addEventListener('load', (e: Event) => {
                    const textTrack = e.currentTarget as HTMLTrackElement;
                    if (t.default === true) {
                        textTrack.track.mode = 'showing';
                        video.textTracks[trackIdx].mode = 'showing'; // thanks Firefox
                    } else {
                        textTrack.track.mode = 'hidden';
                        video.textTracks[trackIdx].mode = 'hidden'; // thanks Firefox
                    }
                });
                video.appendChild(track);
            });
        }
    };

    render() {
        const {
            srcs,
            tracks,
            // Just to omit those props
            playbackRate,
            // onEnded,
            ...mediaProps
        } = this.props;

        const key = srcs && srcs.length > 0 ? srcs[0].src : '';

        return (
            <video
                style={{width: '100%', height: '100%'}}
                onLoadedMetadata={this.onLoadedMetadata}
                ref={this.videoRef}
                {...mediaProps}
                {...(this.props.playsInline ? { 'webkit-playsinline': 'webkit-playsinline' } : {})}
            >
                {srcs && srcs.map((s, idx) => <source key={`${s.src}-${idx}`} {...s} />)}
                {/*
                // This would be so easy, but subsequent changes in tracks will
                // be ignored by firefox. See the workaround onLoadedMetaData function
                {tracks && tracks.map((t, idx) => {
                    return null;
                  return (
                      <track id={`${t.src}-${idx}`} key={`${t.src}-${idx}`} {...t}/>
                  );
                })}
                */}
            </video>
        );
    }

@cookpete, I can add this behaviour to react-player. But I'm not sure it's a nice addition, looks ugly hack and will only be useful for some people. What do you think ?

@cookpete
Copy link
Owner

cookpete commented Oct 5, 2018

@belgattitude I haven't looked too closely at this yet but I did spot this:

One bug I found however is that the default track element must be the first in hierarchy.

https://stackoverflow.com/questions/30992160/video-js-hides-subtitle-for-firefox-how-to-show-it-with-a-generalized-way?rq=1#comment50014582_30992160

Have you tried ensuring that the first track element has default set?

@arkadiusz-wieczorek
Copy link

arkadiusz-wieczorek commented Oct 9, 2018

I've tested the player with first track element which has default set and it doesn't work on Firefox.

@jerlam06
Copy link

Same issue here, subtitles work perfectly on chrome, but don't show up at all on Firefox...

@arkadiusz-wieczorek
Copy link

The solution proposed by @belgattitude works for me.

export default function onLoadedMetadata(e) {
	const video = e.currentTarget;
	const oldTracks = video.querySelectorAll('track');

	for (const track of oldTracks) {
		track.remove();
	}
	if (this.state.config.file.tracks) {
		this.state.config.file.tracks.map((t, trackIdx) => {
			const track = document.createElement('track');
			track.kind = t.kind;
			track.label = t.label;
			track.srclang = t.srcLang;
			track.default = t.default;
			track.src = t.src;

			track.addEventListener('load', e => {
				const textTrack = e.currentTarget;
				if (t.default === true) {
					textTrack.track.mode = 'showing';
					video.textTracks[trackIdx].mode = 'showing'; // thanks Firefox
				} else {
					textTrack.track.mode = 'hidden';
					video.textTracks[trackIdx].mode = 'hidden'; // thanks Firefox
				}
			});
			const video = document.querySelector('video');
			video.appendChild(track);
		});
	}
}

@belgattitude
Copy link
Contributor Author

belgattitude commented Oct 15, 2018

@arkadiusz-wieczorek, @jerlam06

Before using the workaround, could one of you test with the 1.6.4 version of react-player ?

Due to some rush I had rewrite my own player so I cannot test right now... but be warned my workaround was not sufficient for all situations. Debugging was a long long long road... ;)

Tell me and when I have time I'l send a gist with few discoveries I've made. Can be useful

@cookpete
Copy link
Owner

This seems like a problem with React and/or Firefox, and not really with ReactPlayer. The workarounds are impressive but not something I really want to include in the library, especially if:

be warned my workaround was not sufficient for all situations.

You can pass through your own onLoadedMetadata via the config.file.attributes prop, so until a fix is found for the root cause of the problem elsewhere, this will have to do.

Is it worth opening a ticket with React and/or Firefox to try and gain some more wisdom?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants