fix(iframe): Use largeVideo video element for screenshot.

Get the existing HTMLVideoElement for large video instead of creating a new video element for capturing the screenshot.
This should prevent the video player from getting displayed on mobile Safari.
This commit is contained in:
Jaya Allamsetty 2020-09-22 15:45:51 -04:00 committed by Jaya Allamsetty
parent 7a9a6855b7
commit 09124ad7e9
3 changed files with 49 additions and 54 deletions

View File

@ -639,8 +639,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
/** /**
* Captures the screenshot of the large video. * Captures the screenshot of the large video.
* *
* @returns {dataURL} - Base64 encoded image data of the screenshot if large * @returns {Promise<string>} - Resolves with a base64 encoded image data of the screenshot
* video is detected, an error otherwise. * if large video is detected, an error otherwise.
*/ */
captureLargeVideoScreenshot() { captureLargeVideoScreenshot() {
return this._transport.sendRequest({ return this._transport.sendRequest({

View File

@ -9,7 +9,6 @@ import {
import { _handleParticipantError } from '../base/conference'; import { _handleParticipantError } from '../base/conference';
import { MEDIA_TYPE } from '../base/media'; import { MEDIA_TYPE } from '../base/media';
import { getParticipants } from '../base/participants'; import { getParticipants } from '../base/participants';
import { getTrackByMediaTypeAndParticipant } from '../base/tracks';
import { reportError } from '../base/util'; import { reportError } from '../base/util';
import { shouldDisplayTileView } from '../video-layout'; import { shouldDisplayTileView } from '../video-layout';
@ -18,57 +17,6 @@ import {
UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION
} from './actionTypes'; } from './actionTypes';
/**
* Captures a screenshot of the video displayed on the large video.
*
* @returns {Function}
*/
export function captureLargeVideoScreenshot() {
return (dispatch: Dispatch<any>, getState: Function): Promise<Object> => {
const state = getState();
const largeVideo = state['features/large-video'];
if (!largeVideo) {
return Promise.resolve();
}
const tracks = state['features/base/tracks'];
const { jitsiTrack } = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, largeVideo.participantId);
const videoStream = jitsiTrack.getOriginalStream();
// Create a HTML canvas and draw video from the track on to the canvas.
const [ track ] = videoStream.getVideoTracks();
const { height, width } = track.getSettings() ?? track.getConstraints();
const canvasElement = document.createElement('canvas');
const ctx = canvasElement.getContext('2d');
const videoElement = document.createElement('video');
videoElement.height = parseInt(height, 10);
videoElement.width = parseInt(width, 10);
videoElement.autoplay = true;
videoElement.srcObject = videoStream;
canvasElement.height = videoElement.height;
canvasElement.width = videoElement.width;
// Wait for the video to load before drawing on to the canvas.
const promise = new Promise(resolve => {
videoElement.onloadeddata = () => resolve();
});
return promise.then(() => {
ctx.drawImage(videoElement, 0, 0, videoElement.width, videoElement.height);
const dataURL = canvasElement.toDataURL('image/png', 1.0);
// Cleanup.
ctx.clearRect(0, 0, videoElement.width, videoElement.height);
videoElement.srcObject = null;
canvasElement.remove();
videoElement.remove();
return Promise.resolve(dataURL);
});
};
}
/** /**
* Signals conference to select a participant. * Signals conference to select a participant.
* *

View File

@ -3,9 +3,56 @@
import type { Dispatch } from 'redux'; import type { Dispatch } from 'redux';
import VideoLayout from '../../../modules/UI/videolayout/VideoLayout'; import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
import { MEDIA_TYPE } from '../base/media';
import { getTrackByMediaTypeAndParticipant } from '../base/tracks';
export * from './actions.any'; export * from './actions.any';
/**
* Captures a screenshot of the video displayed on the large video.
*
* @returns {Function}
*/
export function captureLargeVideoScreenshot() {
return (dispatch: Dispatch<any>, getState: Function): Promise<string> => {
const state = getState();
const largeVideo = state['features/large-video'];
if (!largeVideo) {
return Promise.resolve();
}
const tracks = state['features/base/tracks'];
const { jitsiTrack } = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, largeVideo.participantId);
const videoStream = jitsiTrack.getOriginalStream();
// Get the video element for the large video, cast HTMLElement to HTMLVideoElement to make flow happy.
/* eslint-disable-next-line no-extra-parens*/
const videoElement = ((document.getElementById('largeVideo'): any): HTMLVideoElement);
if (!videoElement) {
return Promise.resolve();
}
// Create a HTML canvas and draw video on to the canvas.
const [ track ] = videoStream.getVideoTracks();
const { height, width } = track.getSettings() ?? track.getConstraints();
const canvasElement = document.createElement('canvas');
const ctx = canvasElement.getContext('2d');
canvasElement.style.display = 'none';
canvasElement.height = parseInt(height, 10);
canvasElement.width = parseInt(width, 10);
ctx.drawImage(videoElement, 0, 0);
const dataURL = canvasElement.toDataURL('image/png', 1.0);
// Cleanup.
ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
canvasElement.remove();
return Promise.resolve(dataURL);
};
}
/** /**
* Resizes the large video container based on the dimensions provided. * Resizes the large video container based on the dimensions provided.
* *