2018-12-31 01:03:07 +01:00
import Debug from '../../conf/Debug' ;
2021-02-08 23:04:54 +01:00
import AspectRatioType from '../../../common/enums/AspectRatioType.enum' ;
2021-01-30 13:07:19 +01:00
import BrowserDetect from '../../conf/BrowserDetect' ;
2021-02-09 00:42:52 +01:00
import VideoData from '../video-data/VideoData' ;
import Logger from '../Logger' ;
2021-01-30 13:07:19 +01:00
2018-12-31 01:03:07 +01:00
2018-05-06 21:32:18 +02:00
// računa velikost videa za približevanje/oddaljevanje
// does video size calculations for zooming/cropping
class Scaler {
2021-02-09 00:42:52 +01:00
//#region helper objects
conf : VideoData ;
logger : Logger ;
//#endregion
2018-05-06 21:32:18 +02:00
// functions
2019-09-03 22:55:10 +02:00
constructor ( videoData ) {
2018-05-18 23:26:20 +02:00
this . conf = videoData ;
2019-09-03 22:55:10 +02:00
this . logger = videoData . logger ;
2018-05-06 21:32:18 +02:00
}
2019-03-10 23:27:50 +01:00
2019-05-05 00:09:49 +02:00
// Skrbi za "stare" možnosti, kot na primer "na širino zaslona", "na višino zaslona" in "ponastavi".
// Približevanje opuščeno.
2021-02-08 23:04:54 +01:00
// handles "legacy" options, such as 'fit to widht', 'fit to height' and AspectRatioType.Reset. No zoom tho
2019-05-05 00:09:49 +02:00
modeToAr ( ar ) {
2021-02-08 23:04:54 +01:00
if ( ar . type !== AspectRatioType . FitWidth && ar . type !== AspectRatioType . FitHeight && ar . ratio ) {
2019-03-10 23:27:50 +01:00
return ar . ratio ;
}
2019-05-05 00:09:49 +02:00
2019-03-10 23:27:50 +01:00
var ratioOut ;
2018-05-06 21:32:18 +02:00
2018-05-22 00:19:50 +02:00
if ( ! this . conf . video ) {
2019-07-18 21:25:58 +02:00
this . logger . log ( 'error' , 'debug' , "[Scaler.js::modeToAr] No video??" , this . conf . video , "killing videoData" ) ;
2018-05-18 23:26:20 +02:00
this . conf . destroy ( ) ;
2018-05-06 21:32:18 +02:00
return null ;
}
2020-09-20 12:26:03 +02:00
if ( ! this . conf . player . dimensions ) {
2019-03-10 23:27:50 +01:00
ratioOut = screen . width / screen . height ;
2020-09-20 12:26:03 +02:00
} else {
2019-03-10 23:27:50 +01:00
ratioOut = this . conf . player . dimensions . width / this . conf . player . dimensions . height ;
2018-05-06 21:32:18 +02:00
}
2018-08-20 22:45:43 +02:00
// POMEMBNO: lastAr je potrebno nastaviti šele po tem, ko kličemo _res_setAr(). _res_setAr() predvideva,
2018-05-06 21:32:18 +02:00
// da želimo nastaviti statično (type: 'static') razmerje stranic — tudi, če funkcijo kličemo tu oz. v ArDetect.
//
2018-08-20 22:45:43 +02:00
// IMPORTANT NOTE: lastAr needs to be set after _res_setAr() is called, as _res_setAr() assumes we're
2018-05-06 21:32:18 +02:00
// setting a static aspect ratio (even if the function is called from here or ArDetect).
2018-05-22 00:19:50 +02:00
var fileAr = this . conf . video . videoWidth / this . conf . video . videoHeight ;
2018-05-06 21:32:18 +02:00
2021-02-08 23:04:54 +01:00
if ( ar . type === AspectRatioType . FitWidth ) {
2019-03-10 23:27:50 +01:00
ratioOut > fileAr ? ratioOut : fileAr
ar . ratio = ratioOut ;
return ratioOut ;
2018-05-06 21:32:18 +02:00
}
2021-02-08 23:04:54 +01:00
else if ( ar . type === AspectRatioType . FitHeight ) {
2019-03-10 23:27:50 +01:00
ratioOut < fileAr ? ratioOut : fileAr
ar . ratio = ratioOut ;
return ratioOut ;
2018-05-06 21:32:18 +02:00
}
2021-02-08 23:04:54 +01:00
else if ( ar . type === AspectRatioType . Reset ) {
2019-07-18 21:25:58 +02:00
this . logger . log ( 'info' , 'debug' , "[Scaler.js::modeToAr] Using original aspect ratio -" , fileAr )
2019-03-10 23:27:50 +01:00
ar . ar = fileAr ;
2018-05-06 21:32:18 +02:00
return fileAr ;
}
return null ;
}
2019-03-10 23:27:50 +01:00
calculateCrop ( ar ) {
2020-12-18 01:44:45 +01:00
/ * *
* STEP 1 : NORMALIZE ASPECT RATIO
*
* Video width is normalized based on 100 % of the parent . That means if the player AR
* is narrower than video ar , we need to pre - downscale the video . This scaling already
2020-12-19 03:18:14 +01:00
* undoes any zoom that style = "height:123%" on the video element adds .
*
* There are few exceptions and additional caveatss :
2021-02-08 23:04:54 +01:00
* * AspectRatioType.FitHeight : we don ' t want to pre - downscale the video at all , as things
2020-12-19 03:18:14 +01:00
* will be scaled to fit height as - is .
* * When player is wider than stream , we want to undo any height compensations site
* tacks on the video tag .
2020-12-18 01:44:45 +01:00
*
* Quick notes :
* * when I say 'video AR' , I actually mean aspect ratio after we ' ve compensated for
* any possible 'height:' stuffs in the style attribute of the video tag
* * because video width is normalized on 100 % of the parent , we don ' t need to correct
* anything when the player is wider than the video .
* /
const streamAr = this . conf . video . videoWidth / this . conf . video . videoHeight ;
const playerAr = this . conf . player . dimensions . width / this . conf . player . dimensions . height ;
2020-12-19 03:18:14 +01:00
const heightCompensationFactor = this . conf . getHeightCompensationFactor ( ) ;
const compensatedStreamAr = streamAr * heightCompensationFactor ;
2020-12-18 01:44:45 +01:00
let arCorrectionFactor = 1 ;
2020-12-20 01:00:06 +01:00
2021-02-08 23:04:54 +01:00
if ( ar . type !== AspectRatioType . FitHeight ) {
2020-12-20 01:00:06 +01:00
if ( playerAr < compensatedStreamAr ) {
arCorrectionFactor = this . conf . player . dimensions . width / this . conf . video . offsetWidth ;
2021-02-08 23:04:54 +01:00
} else if ( ar . type !== AspectRatioType . Reset ) {
2020-12-20 01:00:06 +01:00
arCorrectionFactor /= heightCompensationFactor ;
}
2020-12-18 01:44:45 +01:00
}
2019-05-07 23:40:13 +02:00
if ( ! this . conf . video ) {
2019-07-18 21:25:58 +02:00
this . logger . log ( 'info' , 'debug' , "[Scaler::calculateCrop] ERROR — no video detected. Conf:" , this . conf , "video:" , this . conf . video , "video dimensions:" , this . conf . video && this . conf . video . videoWidth , '× ' , this . conf . video && this . conf . video . videoHeight ) ;
2018-05-18 23:26:20 +02:00
this . conf . destroy ( ) ;
2018-05-16 23:26:47 +02:00
return { error : "no_video" } ;
}
2019-05-07 23:40:13 +02:00
if ( this . conf . video . videoWidth == 0 || this . conf . video . videoHeight == 0 ) {
// that's illegal, but not illegal enough to just blast our shit to high hell
// mr officer will let you go with a warning this time around
2019-07-18 21:25:58 +02:00
this . logger . log ( 'error' , 'debug' , "[Scaler::calculateCrop] Video has illegal dimensions. Video dimensions:" , this . conf . video && this . conf . video . videoWidth , '× ' , this . conf . video && this . conf . video . videoHeight ) ;
2019-05-07 23:40:13 +02:00
return { error : "illegal_video_dimensions" } ;
}
2018-05-16 23:26:47 +02:00
2021-02-08 23:04:54 +01:00
if ( ar . type === AspectRatioType . Reset ) {
2021-01-31 17:44:24 +01:00
return { xFactor : arCorrectionFactor , yFactor : arCorrectionFactor , arCorrectionFactor : arCorrectionFactor }
2018-05-27 01:29:02 +02:00
}
2018-05-06 21:32:18 +02:00
// handle fuckie-wuckies
2019-05-05 00:09:49 +02:00
if ( ! ar . ratio ) {
2019-07-18 21:25:58 +02:00
this . logger . log ( 'error' , 'scaler' , "[Scaler::calculateCrop] no ar?" , ar . ratio , " -- we were given this mode:" , ar ) ;
2019-04-25 22:02:10 +02:00
return { error : "no_ar" , ratio : ar.ratio } ;
2018-05-06 21:32:18 +02:00
}
2019-07-18 21:25:58 +02:00
this . logger . log ( 'info' , 'scaler' , "[Scaler::calculateCrop] trying to set ar. args are: ar->" , ar . ratio , "; this.conf.player.dimensions->" , this . conf . player . dimensions . width , "× " , this . conf . player . dimensions . height , "| obj:" , this . conf . player . dimensions ) ;
2018-05-06 21:32:18 +02:00
2018-05-23 00:34:18 +02:00
if ( ( ! this . conf . player . dimensions ) || this . conf . player . dimensions . width === 0 || this . conf . player . dimensions . height === 0 ) {
2019-07-18 21:25:58 +02:00
this . logger . log ( 'error' , 'scaler' , "[Scaler::calculateCrop] ERROR — no (or invalid) this.conf.player.dimensions:" , this . conf . player . dimensions ) ;
2018-05-23 00:34:18 +02:00
return { error : "this.conf.player.dimensions_error" } ;
2018-05-06 21:32:18 +02:00
}
// zdaj lahko končno začnemo računati novo velikost videa
// we can finally start computing required video dimensions now:
// Dejansko razmerje stranic datoteke/<video> značke
// Actual aspect ratio of the file/<video> tag
2021-02-08 23:04:54 +01:00
if ( ar . type === AspectRatioType . Initial || ! ar . ratio ) {
2020-12-18 01:44:45 +01:00
ar . ratio = streamAr ;
2019-05-05 00:09:49 +02:00
}
2018-05-06 21:32:18 +02:00
2020-12-18 01:44:45 +01:00
this . logger . log ( 'info' , 'scaler' , "[Scaler::calculateCrop] ar is " , ar . ratio , ", file ar is" , streamAr , ", this.conf.player.dimensions are " , this . conf . player . dimensions . width , "× " , this . conf . player . dimensions . height , "| obj:" , this . conf . player . dimensions ) ;
2018-05-06 21:32:18 +02:00
2021-01-31 23:32:32 +01:00
const videoDimensions = {
2018-05-24 22:49:32 +02:00
xFactor : 1 ,
yFactor : 1 ,
2018-05-06 21:32:18 +02:00
actualWidth : 0 , // width of the video (excluding pillarbox) when <video> tag height is equal to width
actualHeight : 0 , // height of the video (excluding letterbox) when <video> tag height is equal to height
2021-01-31 17:44:24 +01:00
arCorrectionFactor : arCorrectionFactor ,
2018-05-06 21:32:18 +02:00
}
2021-01-31 17:44:24 +01:00
this . calculateCropCore ( videoDimensions , ar . ratio , streamAr , playerAr )
return videoDimensions ;
}
/ * *
* The act of calculating aspect ratio is separated due to resue elsewhere in the extension .
* We are doing that to avoid surprise recursions .
* @param { * } videoDimensions
* @param { * } ar
* @param { * } streamAr
* @param { * } playerAr
* /
calculateCropCore ( videoDimensions , ar , streamAr , playerAr ) {
2020-12-18 01:44:45 +01:00
if ( streamAr < playerAr ) {
2021-01-31 17:44:24 +01:00
if ( streamAr < ar ) {
2019-10-27 22:11:07 +01:00
// in this situation we have to crop letterbox on top/bottom of the player
// we cut it, but never more than the player
2021-01-31 17:44:24 +01:00
videoDimensions . xFactor = Math . min ( ar , playerAr ) / streamAr ;
2018-05-24 22:49:32 +02:00
videoDimensions . yFactor = videoDimensions . xFactor ;
2019-10-27 22:11:07 +01:00
} else {
// in this situation, we would be cutting pillarbox. Inside horizontal player.
// I don't think so. Except exceptions, we'll wait for bug reports.
videoDimensions . xFactor = 1 ;
videoDimensions . yFactor = 1 ;
}
2019-05-05 00:09:49 +02:00
} else {
2021-01-31 17:44:24 +01:00
if ( streamAr < ar || playerAr < ar ) {
2019-10-27 22:11:07 +01:00
// in this situation, we need to add extra letterbox on top of our letterbox
// this means we simply don't crop anything _at all_
2019-10-28 20:33:40 +01:00
videoDimensions . xFactor = 1 ;
videoDimensions . yFactor = 1 ;
2019-10-27 22:11:07 +01:00
} else {
2019-10-28 20:33:40 +01:00
// meant for handling pillarbox crop. not quite implemented.
2020-12-18 01:44:45 +01:00
videoDimensions . xFactor = streamAr / Math . min ( ar . ratio , playerAr ) ;
2019-10-28 20:33:40 +01:00
videoDimensions . yFactor = videoDimensions . xFactor ;
// videoDimensions.xFactor = Math.max(ar.ratio, playerAr) * fileAr;
// videoDimensions.yFactor = videoDimensions.xFactor;
2019-10-27 22:11:07 +01:00
}
2018-05-06 21:32:18 +02:00
}
2021-01-30 12:16:37 +01:00
2021-01-31 17:44:24 +01:00
this . logger . log ( 'info' , 'scaler' , "[Scaler::calculateCrop] Crop factor calculated — " , videoDimensions . xFactor ) ;
// correct the scale factor
if ( videoDimensions . arCorrectionFactor ) {
videoDimensions . xFactor *= videoDimensions . arCorrectionFactor ;
videoDimensions . yFactor *= videoDimensions . arCorrectionFactor ;
2021-01-30 12:16:37 +01:00
}
2021-01-31 23:32:32 +01:00
return videoDimensions ;
2018-05-06 21:32:18 +02:00
}
2018-12-31 01:03:07 +01:00
}
export default Scaler ;