better error handling in video decoding
This commit is contained in:
parent
e8c8455f43
commit
a672b0c78a
2 changed files with 50 additions and 10 deletions
|
@ -106,11 +106,16 @@ export class BaseMediaTile extends MessageTile {
|
||||||
|
|
||||||
get error() {
|
get error() {
|
||||||
if (this._error) {
|
if (this._error) {
|
||||||
return `Could not decrypt media: ${this._error.message}`;
|
return `Could not load media: ${this._error.message}`;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setViewError(err) {
|
||||||
|
this._error = err;
|
||||||
|
this.emitChange("error");
|
||||||
|
}
|
||||||
|
|
||||||
async _loadEncryptedFile(file) {
|
async _loadEncryptedFile(file) {
|
||||||
const blob = await this._mediaRepository.downloadEncryptedFile(file, true);
|
const blob = await this._mediaRepository.downloadEncryptedFile(file, true);
|
||||||
if (this.isDisposed) {
|
if (this.isDisposed) {
|
||||||
|
|
|
@ -15,10 +15,11 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {BaseMediaView} from "./BaseMediaView.js";
|
import {BaseMediaView} from "./BaseMediaView.js";
|
||||||
|
import {domEventAsPromise} from "../../../../dom/utils.js";
|
||||||
|
|
||||||
export class VideoView extends BaseMediaView {
|
export class VideoView extends BaseMediaView {
|
||||||
renderMedia(t, vm) {
|
renderMedia(t) {
|
||||||
return t.video({
|
const video = t.video({
|
||||||
// provide empty data url if video is not decrypted yet.
|
// provide empty data url if video is not decrypted yet.
|
||||||
// Chrome/Electron need this to enable the play button.
|
// Chrome/Electron need this to enable the play button.
|
||||||
src: vm => vm.videoUrl || `data:${vm.mimeType},`,
|
src: vm => vm.videoUrl || `data:${vm.mimeType},`,
|
||||||
|
@ -26,13 +27,47 @@ export class VideoView extends BaseMediaView {
|
||||||
controls: true,
|
controls: true,
|
||||||
preload: "none",
|
preload: "none",
|
||||||
poster: vm => vm.thumbnailUrl,
|
poster: vm => vm.thumbnailUrl,
|
||||||
onPlay: async evt => {
|
onPlay: this._onPlay.bind(this),
|
||||||
if (!vm.videoUrl) {
|
style: vm => `max-width: ${vm.width}px; max-height: ${vm.height}px;${vm.isPending ? "z-index: -1": ""}`
|
||||||
await vm.loadVideo();
|
|
||||||
evt.target.play();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
style: `max-width: ${vm.width}px; max-height: ${vm.height}px;`
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
video.addEventListener("error", this._onError.bind(this));
|
||||||
|
|
||||||
|
return video;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _onPlay(evt) {
|
||||||
|
const vm = this.value;
|
||||||
|
// download and decrypt the video if needed,
|
||||||
|
if (!vm.videoUrl) {
|
||||||
|
try {
|
||||||
|
const video = evt.target;
|
||||||
|
// this will trigger the src to update
|
||||||
|
await vm.loadVideo();
|
||||||
|
// important to only listen for this after src has changed,
|
||||||
|
// or we get the error for the placeholder data url
|
||||||
|
const loadPromise = domEventAsPromise(video, "loadeddata");
|
||||||
|
// now, reload the video and play
|
||||||
|
video.load();
|
||||||
|
await loadPromise;
|
||||||
|
video.play();
|
||||||
|
} catch (err) {/* errors are already caught in error event handler */}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onError(evt) {
|
||||||
|
const vm = this.value;
|
||||||
|
const video = evt.target;
|
||||||
|
const err = video.error;
|
||||||
|
if (err instanceof window.MediaError && err.code === 4) {
|
||||||
|
if (!video.src.startsWith("data:")) {
|
||||||
|
vm.setViewError(new Error(`this browser does not support videos of type ${vm.mimeType}.`));
|
||||||
|
} else {
|
||||||
|
// ignore placeholder url failing to load
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vm.setViewError(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue