import { AfterViewInit , Component , ElementRef , EventEmitter , Input , OnChanges , OnDestroy , Output , Renderer2 , SimpleChanges , ViewChild } from "@angular/core" ; import { ThemePalette } from "@angular/material/core" ; import { EventHandler } from "./interfaces/event-handler.interface" ; import { EventService } from "./services/event.service" ; @ Component ( { selector : "mat-video" , templateUrl : "./video.component.html" , styleUrls : [ "./video.component.scss" , "./styles/icons.scss" ] } ) export class MatVideoComponent implements AfterViewInit , OnChanges , OnDestroy { @ ViewChild ( "player" , { static : false } ) private player : ElementRef ; @ ViewChild ( "video" , { static : false } ) private video : ElementRef ; @ Input ( ) src : string | MediaStream | MediaSource | Blob = null ; @ Input ( ) title : string = null ; @ Input ( ) autoplay = false ; @ Input ( ) preload = true ; @ Input ( ) loop = false ; @ Input ( ) quality = true ; @ Input ( ) fullscreen = true ; @ Input ( ) playsinline = false ; @ Input ( ) showFrameByFrame = false ; @ Input ( ) fps = 29.97 ; @ Input ( ) download = false ; @ Input ( ) color : ThemePalette = "primary" ; @ Input ( ) spinner = "spin" ; @ Input ( ) poster : string = null ; @ Input ( ) keyboard = true ; @ Input ( ) overlay : boolean = null ; @ Input ( ) muted = false ; @ Output ( ) mutedChange = new EventEmitter < boolean > ( ) ; @ Output ( ) timeChange = new EventEmitter < number > ( ) ; @ Input ( ) get time ( ) { return this . getVideoTag ( ) . currentTime ; } set time ( val ) { const video = this . getVideoTag ( ) ; if ( video && val ) { if ( val > video . duration ) { val = video . duration ; } if ( val < 0 ) { val = 0 ; } if ( Math . abs ( val - video . currentTime ) > 0.0001 ) { video . currentTime = val ; } if ( Math . abs ( this . lastTime - video . currentTime ) > 0.0001 ) { setTimeout ( ( ) => this . timeChange . emit ( video . currentTime ) , 0 ) ; this . lastTime = video . currentTime ; } } } playing = false ; isFullscreen = false ; videoWidth : number ; videoHeight : number ; lastTime : number ; videoLoaded = false ; private srcObjectURL : string ; private isMouseMoving = false ; private isMouseMovingTimer : NodeJS . Timer ; private isMouseMovingTimeout = 2000 ; private events : EventHandler [ ] ; constructor ( private renderer , private evt ) { } ngAfterViewInit ( ) { this . events = [ { element : this . video . nativeElement , name : "loadstart" , callback : event => ( this . videoLoaded = false ) , dispose : null } , { element : this . video . nativeElement , name : "loadedmetadata" , callback : event => this . evLoadedMetadata ( event ) , dispose : null } , { element : this . video . nativeElement , name : "error" , callback : event => console . error ( "Unhandled Video Error" , event ) , dispose : null } , { element : this . video . nativeElement , name : "contextmenu" , callback : event => event . preventDefault ( ) , dispose : null } , { element : this . video . nativeElement , name : "timeupdate" , callback : event => this . evTimeUpdate ( event ) , dispose : null } , { element : this . player . nativeElement , name : "mousemove" , callback : event => this . evMouseMove ( event ) , dispose : null } ] ; this . video . nativeElement . onloadeddata = ( ) => ( this . videoLoaded = true ) ; this . evt . addEvents ( this . renderer , this . events ) ; this . setVideoSrc ( this . src ) ; } ngOnChanges ( changes ) { if ( changes . src ) { this . setVideoSrc ( this . src ) ; } } ngOnDestroy ( ) { this . video . nativeElement . onloadeddata = null ; this . evt . removeEvents ( this . events ) ; } load ( ) { if ( this . video && this . video . nativeElement ) { this . video . nativeElement . load ( ) ; } } getVideoTag ( ) { return this . video && this . video . nativeElement ? ( this . video . nativeElement as HTMLVideoElement ) : null ; } evLoadedMetadata ( event ) { this . videoWidth = this . video . nativeElement . videoWidth ; this . videoHeight = this . video . nativeElement . videoHeight ; this . videoLoaded = true ; } evMouseMove ( event ) { this . isMouseMoving = true ; clearTimeout ( this . isMouseMovingTimer ) ; this . isMouseMovingTimer = setTimeout ( ( ) => { this . isMouseMoving = false ; } , this . isMouseMovingTimeout ) ; } evTimeUpdate ( event ) { this . time = this . getVideoTag ( ) . currentTime ; } getOverlayClass ( activeClass , inactiveClass ) { if ( this . overlay === null ) { return ! this . playing || this . isMouseMoving ? activeClass : inactiveClass ; } else { return this . overlay ? activeClass : inactiveClass ; } } private setVideoSrc ( src ) { if ( this . srcObjectURL ) { URL . revokeObjectURL ( this . srcObjectURL ) ; this . srcObjectURL = null ; } if ( ! this . video || ! this . video . nativeElement ) { return ; } if ( ! src ) { this . video . nativeElement . src = null ; if ( "srcObject" in HTMLVideoElement . prototype ) { this . video . nativeElement . srcObject = new MediaStream ( ) ; } } else if ( typeof src === "string" ) { this . video . nativeElement . src = src ; } else if ( "srcObject" in HTMLVideoElement . prototype ) { this . video . nativeElement . srcObject = src ; } else { this . srcObjectURL = URL . createObjectURL ( src ) ; this . video . nativeElement . src = this . srcObjectURL ; } this . video . nativeElement . muted = this . muted ; } }