├── .npmrc ├── .gitignore ├── .npmignore ├── dist ├── utils │ └── string.d.ts ├── index.js ├── framerate-utils.cjs.production.min.js ├── index.d.ts ├── framerate-utils.esm.js ├── framerate-utils.cjs.development.js ├── framerate-utils.cjs.production.min.js.map ├── framerate-utils.esm.js.map └── framerate-utils.cjs.development.js.map ├── src ├── utils │ └── string.ts └── index.ts ├── CHANGELOG.md ├── tsconfig.json ├── package.json ├── README.md └── test └── FrameRate.test.ts /.npmrc: -------------------------------------------------------------------------------- 1 | //registry.npmjs.org/:_authToken=${NPM_TOKEN} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | .idea/ 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .babelrc 3 | .gitignore 4 | yarn.lock 5 | -------------------------------------------------------------------------------- /dist/utils/string.d.ts: -------------------------------------------------------------------------------- 1 | export declare function pad(n: number): string; 2 | export declare function padMs(n: number): string; 3 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict' 3 | 4 | if (process.env.NODE_ENV === 'production') { 5 | module.exports = require('./framerate-utils.cjs.production.min.js') 6 | } else { 7 | module.exports = require('./framerate-utils.cjs.development.js') 8 | } 9 | -------------------------------------------------------------------------------- /src/utils/string.ts: -------------------------------------------------------------------------------- 1 | export function pad(n: number) { 2 | if (n < 10) { 3 | return `0${n.toString(10)}`; 4 | } else { 5 | return n.toString(10); 6 | } 7 | } 8 | 9 | export function padMs(n: number) { 10 | if (n < 10) { 11 | return `00${n.toString(10)}`; 12 | } else if (n < 100) { 13 | return `0${n.toString(10)}`; 14 | } else { 15 | return n.toString(10); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 3.0.1 2 | 3 | - Fixed error message typo 4 | - Added 48fps 5 | 6 | # 3.0.0 7 | 8 | - Added media time conversion (ms and frames) 9 | - Added more tick conversion methods 10 | - Support SRT media format 11 | - Moved repository to Netflix skunkworks 12 | 13 | # 2.0.0 14 | 15 | - Major bump due to breaking change. The exported global variable goes from 16 | bh-framerate to FrameRateUtils. Makes it easier to use without needing `[]` 17 | property access syntax. 18 | 19 | # 1.0.1 20 | 21 | - Remove currently invalid trailing comma from arguments list 22 | 23 | # 1.0.0 24 | 25 | * Initial release 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs 3 | "include": ["src", "types"], 4 | "compilerOptions": { 5 | "module": "esnext", 6 | "lib": ["dom", "esnext"], 7 | "importHelpers": true, 8 | // output .d.ts declaration files for consumers 9 | "declaration": true, 10 | // output .js.map sourcemap files for consumers 11 | "sourceMap": true, 12 | // match output dir to input dir. e.g. dist/index instead of dist/src/index 13 | "rootDir": "./src", 14 | // stricter type-checking for stronger correctness. Recommended by TS 15 | "strict": true, 16 | // linter checks for common issues 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": true, 19 | // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | // use Node's module resolution algorithm, instead of the legacy TS one 23 | "moduleResolution": "node", 24 | // transpile JSX to React.createElement 25 | "jsx": "react", 26 | // interop between ESM and CJS modules. Recommended by TS 27 | "esModuleInterop": true, 28 | // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS 29 | "skipLibCheck": true, 30 | // error out if import and file system have a casing mismatch. Recommended by TS 31 | "forceConsistentCasingInFileNames": true, 32 | // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc` 33 | "noEmit": true, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "framerate-utils", 3 | "version": "4.3.2", 4 | "description": "Utilities to handle frame rate conversion and display", 5 | "main": "dist/index.js", 6 | "typings": "dist/index.d.ts", 7 | "files": [ 8 | "dist" 9 | ], 10 | "engines": { 11 | "node": ">=10" 12 | }, 13 | "scripts": { 14 | "start": "tsdx watch", 15 | "build": "tsdx build", 16 | "test": "tsdx test", 17 | "lint": "tsdx lint", 18 | "prepare": "tsdx build", 19 | "size": "size-limit", 20 | "analyze": "size-limit --why" 21 | }, 22 | "peerDependencies": {}, 23 | "husky": { 24 | "hooks": { 25 | "pre-commit": "tsdx lint" 26 | } 27 | }, 28 | "prettier": { 29 | "printWidth": 80, 30 | "semi": true, 31 | "singleQuote": true, 32 | "trailingComma": "es5" 33 | }, 34 | "repository": { 35 | "type": "git", 36 | "url": "https://github.com/tbranyen/framerate-utils" 37 | }, 38 | "author": "Andy Swan (aswan@netflix.com)", 39 | "contributors": [ 40 | { 41 | "name": "Tim Branyen (@tbranyen)" 42 | } 43 | ], 44 | "license": "MIT", 45 | "module": "dist/framerate-utils.esm.js", 46 | "size-limit": [ 47 | { 48 | "path": "dist/framerate-utils.cjs.production.min.js", 49 | "limit": "10 KB" 50 | }, 51 | { 52 | "path": "dist/framerate-utils.esm.js", 53 | "limit": "10 KB" 54 | } 55 | ], 56 | "devDependencies": { 57 | "@size-limit/preset-small-lib": "^6.0.4", 58 | "husky": "^7.0.4", 59 | "prettier": "^2.7.1", 60 | "size-limit": "^6.0.4", 61 | "tsdx": "^0.14.1", 62 | "tslib": "^2.3.1", 63 | "typescript": "^4.4.4" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JavaScript Framerate Utils 2 | -------------------------- 3 | 4 | Utilities for formatting and converting times to frame rates 5 | 6 | ## Installation 7 | 8 | ``` sh 9 | npm install --save framerate-utils 10 | ``` 11 | 12 | ## Example usage 13 | 14 | ``` js 15 | import { fromTag, secondsToSmpte } from 'framerate-utils'; 16 | 17 | const fr = fromTag('FPS_2397'); 18 | const seconds = 100; 19 | const smpte = secondsToSmpte(fr, seconds); 20 | 21 | console.log(smpte); 22 | // output 00:01:39:21 23 | 24 | ``` 25 | 26 | ## API 27 | 28 | There are numerous functions and constants available for use. While looking 29 | through methods if you come across a `frameRate` argument, you will need to 30 | create one first and pass that in. 31 | 32 | This `FrameRate` object has the following shape: 33 | 34 | ``` js 35 | { 36 | rate: number // The frame rate 37 | numerator: number // The numerator of the frame rate multiplier 38 | denominator: number // The denominator of the frame rate multiplier 39 | dropFrame: bool // drop mode, true - NTSC drop frame, false - non drop frame 40 | fps: number // The effective frame rate in frames per second (rate * (numerator/denominator)) 41 | } 42 | ``` 43 | 44 | And can be created using the following code: 45 | 46 | ``` js 47 | import { create } from 'framerate-utils'; 48 | 49 | const frameRate = create(); 50 | ``` 51 | 52 | ### Constants 53 | 54 | - `SECONDS_PER_HOUR` 55 | - `SECONDS_PER_MINUTE` 56 | - `MILLISECONDS_PER_SECOND` 57 | - `TICKS_PER_SECOND` 58 | 59 | ### Functions 60 | 61 | - `create(rate = 24, numerator = 1, denominator = 1, dropFrame = false)` - Creates a new FrameRate object 62 | - `secondsToSmpte(frameRate, seconds)` - Returns seconds converted to SMPTE time. 63 | - `smpteToSeconds(frameRate, smtpe)` - Returns SMPTE time converted to seconds. 64 | - `smpteToMs` - Returns SMPTE time converted to milliseconds. 65 | - `msToSmpte` - Returns milliseconds converted to SMPTE time. 66 | 67 | For all functions view the `src/index.ts` file. 68 | -------------------------------------------------------------------------------- /dist/framerate-utils.cjs.production.min.js: -------------------------------------------------------------------------------- 1 | "use strict";function e(e){return e<10?"0"+e.toString(10):e.toString(10)}Object.defineProperty(exports,"__esModule",{value:!0});var r=Math.round,t=Math.ceil,n=Math.floor,o=Math.max,s=F(24,1e3,1001),a=F(24,1,1),p=F(25,1,1),u=F(30,1e3,1001),c=F(30,1e3,1001,!0),i=F(30,1,1),f=F(48,1e3,1001),x=F(48,1,1),_=F(50,1,1),T=F(60,1e3,1001),S=F(60,1e3,1001,!0),m=F(60,1,1);function F(e,r,t,n){return void 0===e&&(e=24),void 0===r&&(r=1),void 0===t&&(t=1),void 0===n&&(n=!1),{rate:e,numerator:r,denominator:t,fps:e*r/t,dropFrame:n}}function d(e,r){return P(e,R(e,r))}function E(e,r){return l(e,M(e,r))}function R(e,r){return n(r*e.fps+.002*e.fps)}function P(t,o){var s=(o+v(t,o))/t.rate,a=r((s-n(s))*t.rate),p=n(s/3600),u=n(s%3600/60),c=n(s%60),i=t.dropFrame?";":":";return e(p)+":"+e(u)+":"+e(c)+i+e(a)}function I(e,r){return Math.floor(e/r)}function v(e,r){if(!e.dropFrame)return 0;var t=17982,n=2;60===e.rate&&(t=35964,n=4);var s=I(r,t),a=r%t;return a { 16 | it('should convert drop frame to smpte correctly', () => { 17 | expect(FrameRate.frameToSmpte(FrameRate.RATE_29_97_DROP, 1798)).toEqual( 18 | '00:00:59;28' 19 | ); 20 | expect(FrameRate.frameToSmpte(FrameRate.RATE_29_97_DROP, 1799)).toEqual( 21 | '00:00:59;29' 22 | ); 23 | expect(FrameRate.frameToSmpte(FrameRate.RATE_29_97_DROP, 1800)).toEqual( 24 | '00:01:00;02' 25 | ); 26 | expect(FrameRate.frameToSmpte(FrameRate.RATE_29_97_DROP, 1801)).toEqual( 27 | '00:01:00;03' 28 | ); 29 | expect(FrameRate.frameToSmpte(FrameRate.RATE_29_97_DROP, 8990)).toEqual( 30 | '00:04:59;28' 31 | ); 32 | expect(FrameRate.frameToSmpte(FrameRate.RATE_29_97_DROP, 8991)).toEqual( 33 | '00:04:59;29' 34 | ); 35 | expect(FrameRate.frameToSmpte(FrameRate.RATE_29_97_DROP, 8992)).toEqual( 36 | '00:05:00;02' 37 | ); 38 | expect(FrameRate.frameToSmpte(FrameRate.RATE_29_97_DROP, 17980)).toEqual( 39 | '00:09:59;28' 40 | ); 41 | expect(FrameRate.frameToSmpte(FrameRate.RATE_29_97_DROP, 17981)).toEqual( 42 | '00:09:59;29' 43 | ); 44 | expect(FrameRate.frameToSmpte(FrameRate.RATE_29_97_DROP, 17982)).toEqual( 45 | '00:10:00;00' 46 | ); 47 | expect(FrameRate.frameToSmpte(FrameRate.RATE_29_97_DROP, 17983)).toEqual( 48 | '00:10:00;01' 49 | ); 50 | expect(FrameRate.frameToSmpte(FrameRate.RATE_29_97_DROP, 17984)).toEqual( 51 | '00:10:00;02' 52 | ); 53 | }); 54 | 55 | it('should convert smpte to drop frame correctly', () => { 56 | expect( 57 | FrameRate.smpteToFrame(FrameRate.RATE_29_97_DROP, '00:00:59;28') 58 | ).toEqual(1798); 59 | expect( 60 | FrameRate.smpteToFrame(FrameRate.RATE_29_97_DROP, '00:00:59;29') 61 | ).toEqual(1799); 62 | expect( 63 | FrameRate.smpteToFrame(FrameRate.RATE_29_97_DROP, '00:01:00;02') 64 | ).toEqual(1800); 65 | expect( 66 | FrameRate.smpteToFrame(FrameRate.RATE_29_97_DROP, '00:01:00;03') 67 | ).toEqual(1801); 68 | expect( 69 | FrameRate.smpteToFrame(FrameRate.RATE_29_97_DROP, '00:04:59;28') 70 | ).toEqual(8990); 71 | expect( 72 | FrameRate.smpteToFrame(FrameRate.RATE_29_97_DROP, '00:04:59;29') 73 | ).toEqual(8991); 74 | expect( 75 | FrameRate.smpteToFrame(FrameRate.RATE_29_97_DROP, '00:05:00;02') 76 | ).toEqual(8992); 77 | expect( 78 | FrameRate.smpteToFrame(FrameRate.RATE_29_97_DROP, '00:09:59;28') 79 | ).toEqual(17980); 80 | expect( 81 | FrameRate.smpteToFrame(FrameRate.RATE_29_97_DROP, '00:09:59;29') 82 | ).toEqual(17981); 83 | expect( 84 | FrameRate.smpteToFrame(FrameRate.RATE_29_97_DROP, '00:10:00;00') 85 | ).toEqual(17982); 86 | expect( 87 | FrameRate.smpteToFrame(FrameRate.RATE_29_97_DROP, '00:10:00;01') 88 | ).toEqual(17983); 89 | expect( 90 | FrameRate.smpteToFrame(FrameRate.RATE_29_97_DROP, '00:10:00;02') 91 | ).toEqual(17984); 92 | }); 93 | 94 | it('should convert 59.94 drop frame to smpte correctly', () => { 95 | expect(FrameRate.frameToSmpte(FrameRate.RATE_59_94_DROP, 3598)).toEqual( 96 | '00:00:59;58' 97 | ); 98 | expect(FrameRate.frameToSmpte(FrameRate.RATE_59_94_DROP, 3599)).toEqual( 99 | '00:00:59;59' 100 | ); 101 | expect(FrameRate.frameToSmpte(FrameRate.RATE_59_94_DROP, 3600)).toEqual( 102 | '00:01:00;04' 103 | ); 104 | expect(FrameRate.frameToSmpte(FrameRate.RATE_59_94_DROP, 3601)).toEqual( 105 | '00:01:00;05' 106 | ); 107 | expect(FrameRate.frameToSmpte(FrameRate.RATE_59_94_DROP, 17982)).toEqual( 108 | '00:04:59;58' 109 | ); 110 | expect(FrameRate.frameToSmpte(FrameRate.RATE_59_94_DROP, 17983)).toEqual( 111 | '00:04:59;59' 112 | ); 113 | expect(FrameRate.frameToSmpte(FrameRate.RATE_59_94_DROP, 17984)).toEqual( 114 | '00:05:00;04' 115 | ); 116 | expect(FrameRate.frameToSmpte(FrameRate.RATE_59_94_DROP, 35962)).toEqual( 117 | '00:09:59;58' 118 | ); 119 | expect(FrameRate.frameToSmpte(FrameRate.RATE_59_94_DROP, 35963)).toEqual( 120 | '00:09:59;59' 121 | ); 122 | expect(FrameRate.frameToSmpte(FrameRate.RATE_59_94_DROP, 35964)).toEqual( 123 | '00:10:00;00' 124 | ); 125 | expect(FrameRate.frameToSmpte(FrameRate.RATE_59_94_DROP, 35965)).toEqual( 126 | '00:10:00;01' 127 | ); 128 | expect(FrameRate.frameToSmpte(FrameRate.RATE_59_94_DROP, 35966)).toEqual( 129 | '00:10:00;02' 130 | ); 131 | }); 132 | 133 | it('should convert 59.94 smpte to drop frame correctly', () => { 134 | expect( 135 | FrameRate.smpteToFrame(FrameRate.RATE_59_94_DROP, '00:00:59;58') 136 | ).toEqual(3598); 137 | expect( 138 | FrameRate.smpteToFrame(FrameRate.RATE_59_94_DROP, '00:00:59;59') 139 | ).toEqual(3599); 140 | expect( 141 | FrameRate.smpteToFrame(FrameRate.RATE_59_94_DROP, '00:01:00;04') 142 | ).toEqual(3600); 143 | expect( 144 | FrameRate.smpteToFrame(FrameRate.RATE_59_94_DROP, '00:01:00;05') 145 | ).toEqual(3601); 146 | expect( 147 | FrameRate.smpteToFrame(FrameRate.RATE_59_94_DROP, '00:04:59;58') 148 | ).toEqual(17982); 149 | expect( 150 | FrameRate.smpteToFrame(FrameRate.RATE_59_94_DROP, '00:04:59;59') 151 | ).toEqual(17983); 152 | expect( 153 | FrameRate.smpteToFrame(FrameRate.RATE_59_94_DROP, '00:05:00;04') 154 | ).toEqual(17984); 155 | expect( 156 | FrameRate.smpteToFrame(FrameRate.RATE_59_94_DROP, '00:09:59;58') 157 | ).toEqual(35962); 158 | expect( 159 | FrameRate.smpteToFrame(FrameRate.RATE_59_94_DROP, '00:09:59;59') 160 | ).toEqual(35963); 161 | expect( 162 | FrameRate.smpteToFrame(FrameRate.RATE_59_94_DROP, '00:10:00;00') 163 | ).toEqual(35964); 164 | expect( 165 | FrameRate.smpteToFrame(FrameRate.RATE_59_94_DROP, '00:10:00;01') 166 | ).toEqual(35965); 167 | expect( 168 | FrameRate.smpteToFrame(FrameRate.RATE_59_94_DROP, '00:10:00;02') 169 | ).toEqual(35966); 170 | }); 171 | 172 | it('should convert 00:00:10:01 correctly', () => { 173 | const fr = FrameRate.RATE_23_976; 174 | const frame = FrameRate.secondsToFrame(fr, 10.052); 175 | const actual = FrameRate.toFrameTime(fr, 10.052); 176 | const rounded = Math.round(actual * 100) / 100; 177 | const smpte = FrameRate.secondsToSmpte(fr, actual); 178 | 179 | expect(frame).toEqual(241); 180 | expect(rounded).toEqual(10.07); 181 | expect(smpte).toEqual('00:00:10:01'); 182 | }); 183 | 184 | it('should convert 00:00:23:03 correctly', () => { 185 | const fr = FrameRate.RATE_23_976; 186 | const frame = FrameRate.secondsToFrame(fr, 23.149); 187 | const actual = FrameRate.toFrameTime(fr, 23.149); 188 | const rounded = Math.round(actual * 100) / 100; 189 | const smpte = FrameRate.secondsToSmpte(fr, actual); 190 | 191 | expect(frame).toEqual(555); 192 | expect(rounded).toEqual(23.17); 193 | expect(smpte).toEqual('00:00:23:03'); 194 | }); 195 | 196 | it('should convert 00:00:01:00 correctly', () => { 197 | const fr = FrameRate.RATE_23_976; 198 | const frame23 = FrameRate.secondsToFrame(fr, 0.998); 199 | const frame24 = FrameRate.secondsToFrame(fr, 1.001); 200 | 201 | expect(frame23).toEqual(23); 202 | expect(frame24).toEqual(24); 203 | }); 204 | 205 | it('should parse mm:ss:ff correctly', () => { 206 | const fr = FrameRate.RATE_24; 207 | 208 | expect(FrameRate.smpteToFrame(fr, '01:02:03')).toEqual(1491); 209 | }); 210 | 211 | it('should avoid rounding error on frame to ms', () => { 212 | const fr = FrameRate.RATE_23_976; 213 | const frame = 473; 214 | const ms = FrameRate.frameToMs(fr, frame); 215 | const actual = FrameRate.msToFrame(fr, ms); 216 | 217 | expect(actual).toEqual(frame); 218 | }); 219 | 220 | it('should parse drop frame', () => { 221 | const fr = FrameRate.RATE_29_97_DROP; 222 | 223 | expect(FrameRate.smpteToMs(fr, '00:01:00;03')).toEqual(60094); 224 | expect(FrameRate.smpteToMs(fr, '01:11:23;07')).toEqual(4283246); 225 | }); 226 | 227 | it('should format drop frame', () => { 228 | const fr = FrameRate.RATE_29_97_DROP; 229 | 230 | expect(FrameRate.msToSmpte(fr, 60094)).toEqual('00:01:00;03'); 231 | expect(FrameRate.msToSmpte(fr, 60091)).toEqual('00:01:00;02'); 232 | expect(FrameRate.msToSmpte(fr, 4283246)).toEqual('01:11:23;07'); 233 | expect(FrameRate.msToSmpte(fr, 4283243)).toEqual('01:11:23;06'); 234 | expect(FrameRate.msToSmpte(fr, 0)).toEqual('00:00:00;00'); 235 | }); 236 | 237 | it('should convert seconds to smpte', () => { 238 | const fr = FrameRate.fromTag('FPS_2397'); 239 | const seconds = 100; 240 | 241 | expect(FrameRate.secondsToSmpte(fr, seconds)).toEqual('00:01:39:21'); 242 | }); 243 | 244 | it('should convert ms to seconds', () => { 245 | expect(FrameRate.msToSeconds(2500)).toEqual(2.5); 246 | }); 247 | 248 | it('should convert seconds to ms', () => { 249 | expect(FrameRate.secondsToMs(4.123)).toEqual(4123); 250 | }); 251 | 252 | it('should convert seconds to ticks', () => { 253 | expect(FrameRate.secondsToTicks(2.5)).toEqual(25000000); 254 | expect(FrameRate.secondsToTicks(1.23456789)).toEqual(12345678); 255 | }); 256 | 257 | it('should convert ticks to seconds', () => { 258 | expect(FrameRate.secondsToTicks(3.14)).toEqual(31400000); 259 | }); 260 | 261 | it('should convert media to seconds', () => { 262 | expect(FrameRate.mediaToSeconds('01:02:03.456')).toEqual(3723.456); 263 | }); 264 | 265 | it('should convert seconds to media', () => { 266 | expect(FrameRate.secondsToMedia(10921.7654)).toEqual('03:02:01.765'); 267 | expect(FrameRate.secondsToMedia(10921.7657)).toEqual('03:02:01.766'); 268 | expect(FrameRate.secondsToMedia(1.011)).toEqual('00:00:01.011'); 269 | expect(FrameRate.secondsToMedia(1.003)).toEqual('00:00:01.003'); 270 | }); 271 | 272 | it('should convert media frames to seconds', () => { 273 | const fr = FrameRate.RATE_24; 274 | expect(FrameRate.mediaFramesToSeconds(fr, '01:02:03:06')).toEqual(3723.25); 275 | }); 276 | 277 | it('should convert seconds to media', () => { 278 | const fr = FrameRate.RATE_25; 279 | expect(FrameRate.secondsToMediaFrames(fr, 10921.12)).toEqual('03:02:01:03'); 280 | expect(FrameRate.secondsToMediaFrames(fr, 10921.8)).toEqual('03:02:01:20'); 281 | }); 282 | 283 | it('should convert SRT media media to seconds', () => { 284 | expect(FrameRate.mediaToSeconds('01:02:03,456')).toEqual(3723.456); 285 | }); 286 | 287 | it('should support all frame rates from tag', () => { 288 | expect(FrameRate.fromTag('FPS_2397')).toEqual(RATE_23_976); 289 | expect(FrameRate.fromTag('FPS_24')).toEqual(RATE_24); 290 | expect(FrameRate.fromTag('FPS_2400')).toEqual(RATE_24); 291 | expect(FrameRate.fromTag('FPS_25')).toEqual(RATE_25); 292 | expect(FrameRate.fromTag('FPS_2500')).toEqual(RATE_25); 293 | expect(FrameRate.fromTag('FPS_2997')).toEqual(RATE_29_97_DROP); 294 | expect(FrameRate.fromTag('FPS_30')).toEqual(RATE_30); 295 | expect(FrameRate.fromTag('FPS_3000')).toEqual(RATE_30); 296 | expect(FrameRate.fromTag('FPS_4795')).toEqual(RATE_47_95); 297 | expect(FrameRate.fromTag('FPS_48')).toEqual(RATE_48); 298 | expect(FrameRate.fromTag('FPS_4800')).toEqual(RATE_48); 299 | expect(FrameRate.fromTag('FPS_50')).toEqual(RATE_50); 300 | expect(FrameRate.fromTag('FPS_5000')).toEqual(RATE_50); 301 | expect(FrameRate.fromTag('FPS_5994')).toEqual(RATE_59_94_DROP); 302 | expect(FrameRate.fromTag('FPS_60')).toEqual(RATE_60); 303 | expect(FrameRate.fromTag('FPS_6000')).toEqual(RATE_60); 304 | }); 305 | 306 | it('converts to media correctly', () => { 307 | const rate = FrameRate.fromTag('FPS_2997'); 308 | const seconds = FrameRate.smpteToSeconds(rate, '00:53:23;00'); 309 | // 3202.9998 310 | console.log(seconds); 311 | expect(FrameRate.secondsToMedia(seconds)).toEqual('00:53:23.000'); 312 | }); 313 | }); 314 | -------------------------------------------------------------------------------- /dist/framerate-utils.cjs.development.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | 5 | function pad(n) { 6 | if (n < 10) { 7 | return "0" + n.toString(10); 8 | } else { 9 | return n.toString(10); 10 | } 11 | } 12 | function padMs(n) { 13 | if (n < 10) { 14 | return "00" + n.toString(10); 15 | } else if (n < 100) { 16 | return "0" + n.toString(10); 17 | } else { 18 | return n.toString(10); 19 | } 20 | } 21 | 22 | var round = Math.round, 23 | ceil = Math.ceil, 24 | floor = Math.floor, 25 | max = Math.max; 26 | var SECONDS_PER_HOUR = 60 * 60; 27 | var SECONDS_PER_MINUTE = 60; 28 | var MILLISECONDS_PER_SECOND = 1000; 29 | var TICKS_PER_SECOND = 10000000; 30 | var RATE_23_976 = /*#__PURE__*/create(24, 1000, 1001); 31 | var RATE_24 = /*#__PURE__*/create(24, 1, 1); 32 | var RATE_25 = /*#__PURE__*/create(25, 1, 1); 33 | var RATE_29_97 = /*#__PURE__*/create(30, 1000, 1001); 34 | var RATE_29_97_DROP = /*#__PURE__*/create(30, 1000, 1001, true); 35 | var RATE_30 = /*#__PURE__*/create(30, 1, 1); 36 | var RATE_47_95 = /*#__PURE__*/create(48, 1000, 1001); 37 | var RATE_48 = /*#__PURE__*/create(48, 1, 1); 38 | var RATE_50 = /*#__PURE__*/create(50, 1, 1); 39 | var RATE_59_94 = /*#__PURE__*/create(60, 1000, 1001); 40 | var RATE_59_94_DROP = /*#__PURE__*/create(60, 1000, 1001, true); 41 | var RATE_60 = /*#__PURE__*/create(60, 1, 1); 42 | var DEFAULT_FRAME_RATE = RATE_23_976; 43 | /* 44 | * Adjustment required to account for rounding of input data. 45 | * For example: 46 | * frame 836 @ 24fps = 34.83333333333333s 47 | * This can be rounded by input format to 34833ms 48 | * 34833ms @ 24fps is frame 835.992 which will be treated as frame 835. 49 | * To adjust for this 0.001s will be added before truncating. 50 | * 51 | * Update: Rounding with CAP files can cause up to 2ms difference, so update 52 | * rounding to up to 2ms. 53 | */ 54 | 55 | var FRAME_ROUNDING = 0.002; 56 | function create(rate, numerator, denominator, dropFrame) { 57 | if (rate === void 0) { 58 | rate = 24; 59 | } 60 | 61 | if (numerator === void 0) { 62 | numerator = 1; 63 | } 64 | 65 | if (denominator === void 0) { 66 | denominator = 1; 67 | } 68 | 69 | if (dropFrame === void 0) { 70 | dropFrame = false; 71 | } 72 | 73 | return { 74 | rate: rate, 75 | numerator: numerator, 76 | denominator: denominator, 77 | fps: rate * numerator / denominator, 78 | dropFrame: dropFrame 79 | }; 80 | } 81 | function secondsToSmpte(frameRate, seconds) { 82 | return frameToSmpte(frameRate, secondsToFrame(frameRate, seconds)); 83 | } 84 | function smpteToSeconds(frameRate, smpte) { 85 | return frameToSeconds(frameRate, smpteToFrame(frameRate, smpte)); 86 | } 87 | function smpteToMs(frameRate, smpte) { 88 | return ceil(smpteToSeconds(frameRate, smpte) * MILLISECONDS_PER_SECOND); 89 | } 90 | function msToSmpte(frameRate, ms) { 91 | return secondsToSmpte(frameRate, ms / MILLISECONDS_PER_SECOND); 92 | } 93 | function smpteToTicks(frameRate, smpte) { 94 | return ceil(smpteToSeconds(frameRate, smpte) * TICKS_PER_SECOND); 95 | } 96 | function ticksToSmpte(frameRate, ticks) { 97 | return secondsToSmpte(frameRate, ticks / TICKS_PER_SECOND); 98 | } 99 | function secondsToFrame(frameRate, seconds) { 100 | var frame = seconds * frameRate.fps + FRAME_ROUNDING * frameRate.fps; 101 | return floor(frame); 102 | } 103 | function msToFrame(frameRate, ms) { 104 | return secondsToFrame(frameRate, ms / MILLISECONDS_PER_SECOND); 105 | } 106 | function frameToMs(frameRate, frame) { 107 | return ceil(frameToSeconds(frameRate, frame) * MILLISECONDS_PER_SECOND); 108 | } 109 | function ticksToFrame(frameRate, ticks) { 110 | return secondsToFrame(frameRate, ticks / TICKS_PER_SECOND); 111 | } 112 | function frameToTicks(frameRate, frame) { 113 | return ceil(frameToSeconds(frameRate, frame) * TICKS_PER_SECOND); 114 | } 115 | function frameToSmpte(frameRate, frame) { 116 | var extra = extraFrames(frameRate, frame); 117 | var seconds = (frame + extra) / frameRate.rate; 118 | var f = round((seconds - floor(seconds)) * frameRate.rate); 119 | var h = floor(seconds / SECONDS_PER_HOUR); 120 | var m = floor(seconds % SECONDS_PER_HOUR / SECONDS_PER_MINUTE); 121 | var s = floor(seconds % SECONDS_PER_MINUTE); 122 | var frameSeparator = frameRate.dropFrame ? ';' : ':'; 123 | return pad(h) + ":" + pad(m) + ":" + pad(s) + frameSeparator + pad(f); 124 | } 125 | 126 | function div(dividend, divisor) { 127 | return Math.floor(dividend / divisor); 128 | } 129 | /** 130 | * Return the number of extra frames required to convert drop frame to 131 | * SMPTE timecode. 132 | * Based on calculation from http://andrewduncan.net/timecodes/ 133 | * D = frameNumber div 17982 134 | * M = frameNumber mod 17982 135 | * frameNumber += 18*D + 2*((M - 2) div 1798) 136 | * See also https://video.stackexchange.com/questions/22722/how-are-frames-in-59-94-drop-frame-timecode-dropped/22724#22724 137 | * for support for 59.94fps 138 | * 139 | * @param {FrameRate} frameRate The frame rate to use for conversion 140 | * @param {Number} frame The actual number of frames 141 | * @returns {Number} The extra frames required 142 | */ 143 | 144 | 145 | function extraFrames(frameRate, frame) { 146 | if (!frameRate.dropFrame) { 147 | return 0; 148 | } 149 | 150 | var framesPer10Mins = 17982; 151 | var dropFrames = 2; 152 | 153 | if (frameRate.rate === 60) { 154 | framesPer10Mins = 35964; 155 | dropFrames = 4; 156 | } 157 | 158 | var D = div(frame, framesPer10Mins); 159 | var M = frame % framesPer10Mins; 160 | 161 | if (M < dropFrames) { 162 | // Special case for M=0 and M=1: -2 div 1798 should be 0 163 | M = dropFrames; 164 | } 165 | 166 | return max(0, 9 * dropFrames * D + dropFrames * div(M - dropFrames, div(framesPer10Mins, 10))); 167 | } // Return the number of frames to subtract to convert smpte drop frame 168 | // back to frame number. 169 | // http://andrewduncan.net/timecodes/ 170 | // totalMinutes = 60 * hours + minutes 171 | // frameNumber = 108000 * hours + 1800 * minutes 172 | // + 30 * seconds + frames 173 | // - 2 * (totalMinutes - totalMinutes div 10) 174 | 175 | function subtractFrames(frameRate, h, m) { 176 | if (!frameRate.dropFrame) { 177 | return 0; 178 | } 179 | 180 | var dropFrames = 2; 181 | 182 | if (frameRate.rate === 60) { 183 | dropFrames = 4; 184 | } 185 | 186 | var totalMinutes = h * 60 + m; 187 | return dropFrames * (totalMinutes - div(totalMinutes, 10)); 188 | } 189 | function smpteToFrame(frameRate, smpte) { 190 | var parts = smpte.split(/:|;/); 191 | var h, m, s, f; 192 | 193 | if (parts.length === 3) { 194 | h = 0; 195 | m = parseInt(parts[0]); 196 | s = parseInt(parts[1]); 197 | f = parseInt(parts[2]); 198 | } else if (parts.length === 4) { 199 | h = parseInt(parts[0]); 200 | m = parseInt(parts[1]); 201 | s = parseInt(parts[2]); 202 | f = parseInt(parts[3]); 203 | } else { 204 | return 0; 205 | } 206 | 207 | var seconds = h * SECONDS_PER_HOUR + m * SECONDS_PER_MINUTE + s; 208 | var frames = seconds * frameRate.rate + f; 209 | return frames - subtractFrames(frameRate, h, m); 210 | } 211 | function frameToSeconds(frameRate, frame) { 212 | return frame / frameRate.fps; 213 | } 214 | function seekByFrames(frameRate, fromTimeSeconds, frameDelta) { 215 | var frame = secondsToFrame(frameRate, fromTimeSeconds); 216 | return seekToFrame(frameRate, frame + frameDelta); 217 | } 218 | function seekToFrame(frameRate, frame) { 219 | var newTime = frameToSeconds(frameRate, frame); 220 | var halfFrame = frameToSeconds(frameRate, 1) / 2; // add half frame to ensure the resulting time is in the frame 221 | 222 | return newTime + halfFrame; 223 | } 224 | function toFrameTime(frameRate, seconds) { 225 | return seekByFrames(frameRate, seconds, 0); 226 | } 227 | function mediaToSeconds(media) { 228 | var parts = media.split(/:|\.|,/); 229 | var h, m, s, ms; 230 | 231 | if (parts.length === 4) { 232 | h = parseInt(parts[0]); 233 | m = parseInt(parts[1]); 234 | s = parseInt(parts[2]); 235 | ms = parseInt(parts[3]); 236 | } else { 237 | return 0; 238 | } 239 | 240 | var seconds = h * SECONDS_PER_HOUR + m * SECONDS_PER_MINUTE + s; 241 | return seconds + ms / 1000; 242 | } 243 | function secondsToMedia(seconds) { 244 | var milliseconds = round(seconds * MILLISECONDS_PER_SECOND); 245 | var sec = floor(milliseconds / MILLISECONDS_PER_SECOND); 246 | var ms = milliseconds % MILLISECONDS_PER_SECOND; 247 | var h = floor(sec / SECONDS_PER_HOUR); 248 | var m = floor(sec % SECONDS_PER_HOUR / SECONDS_PER_MINUTE); 249 | var s = floor(sec % SECONDS_PER_MINUTE); 250 | return pad(h) + ':' + pad(m) + ':' + pad(s) + '.' + padMs(ms); 251 | } 252 | function mediaFramesToSeconds(fr, media) { 253 | var parts = media.split(/:/); 254 | var h, m, s, f; 255 | 256 | if (parts.length === 4) { 257 | h = parseInt(parts[0]); 258 | m = parseInt(parts[1]); 259 | s = parseInt(parts[2]); 260 | f = parseInt(parts[3]); 261 | } else { 262 | return 0; 263 | } 264 | 265 | var seconds = h * SECONDS_PER_HOUR + m * SECONDS_PER_MINUTE + s; 266 | return seconds + f / fr.fps; 267 | } 268 | function secondsToMediaFrames(fr, seconds) { 269 | var sec = floor(seconds); 270 | var f = round((seconds - sec) * fr.fps); 271 | var h = floor(sec / SECONDS_PER_HOUR); 272 | var m = floor(sec % SECONDS_PER_HOUR / SECONDS_PER_MINUTE); 273 | var s = floor(sec % SECONDS_PER_MINUTE); 274 | return pad(h) + ':' + pad(m) + ':' + pad(s) + ':' + pad(f); 275 | } 276 | function ticksToSeconds(ticks) { 277 | return ticks / TICKS_PER_SECOND; 278 | } 279 | function secondsToTicks(seconds) { 280 | return floor(seconds * TICKS_PER_SECOND); 281 | } 282 | function msToSeconds(ms) { 283 | return ms / MILLISECONDS_PER_SECOND; 284 | } 285 | function secondsToMs(seconds) { 286 | return seconds * MILLISECONDS_PER_SECOND; 287 | } 288 | function fromTag(tag) { 289 | switch (tag) { 290 | case 'FPS_2397': 291 | return RATE_23_976; 292 | 293 | case 'FPS_24': 294 | return RATE_24; 295 | 296 | case 'FPS_2400': 297 | return RATE_24; 298 | 299 | case 'FPS_25': 300 | return RATE_25; 301 | 302 | case 'FPS_2500': 303 | return RATE_25; 304 | 305 | case 'FPS_2997': 306 | return RATE_29_97_DROP; 307 | 308 | case 'FPS_30': 309 | return RATE_30; 310 | 311 | case 'FPS_3000': 312 | return RATE_30; 313 | 314 | case 'FPS_4795': 315 | return RATE_47_95; 316 | 317 | case 'FPS_48': 318 | return RATE_48; 319 | 320 | case 'FPS_4800': 321 | return RATE_48; 322 | 323 | case 'FPS_50': 324 | return RATE_50; 325 | 326 | case 'FPS_5000': 327 | return RATE_50; 328 | 329 | case 'FPS_5994': 330 | return RATE_59_94_DROP; 331 | 332 | case 'FPS_60': 333 | return RATE_60; 334 | 335 | case 'FPS_6000': 336 | return RATE_60; 337 | 338 | default: 339 | throw new TypeError("Unknown Frame Rate " + tag); 340 | } 341 | } 342 | 343 | exports.DEFAULT_FRAME_RATE = DEFAULT_FRAME_RATE; 344 | exports.FRAME_ROUNDING = FRAME_ROUNDING; 345 | exports.MILLISECONDS_PER_SECOND = MILLISECONDS_PER_SECOND; 346 | exports.RATE_23_976 = RATE_23_976; 347 | exports.RATE_24 = RATE_24; 348 | exports.RATE_25 = RATE_25; 349 | exports.RATE_29_97 = RATE_29_97; 350 | exports.RATE_29_97_DROP = RATE_29_97_DROP; 351 | exports.RATE_30 = RATE_30; 352 | exports.RATE_47_95 = RATE_47_95; 353 | exports.RATE_48 = RATE_48; 354 | exports.RATE_50 = RATE_50; 355 | exports.RATE_59_94 = RATE_59_94; 356 | exports.RATE_59_94_DROP = RATE_59_94_DROP; 357 | exports.RATE_60 = RATE_60; 358 | exports.SECONDS_PER_HOUR = SECONDS_PER_HOUR; 359 | exports.SECONDS_PER_MINUTE = SECONDS_PER_MINUTE; 360 | exports.TICKS_PER_SECOND = TICKS_PER_SECOND; 361 | exports.create = create; 362 | exports.extraFrames = extraFrames; 363 | exports.frameToMs = frameToMs; 364 | exports.frameToSeconds = frameToSeconds; 365 | exports.frameToSmpte = frameToSmpte; 366 | exports.frameToTicks = frameToTicks; 367 | exports.fromTag = fromTag; 368 | exports.mediaFramesToSeconds = mediaFramesToSeconds; 369 | exports.mediaToSeconds = mediaToSeconds; 370 | exports.msToFrame = msToFrame; 371 | exports.msToSeconds = msToSeconds; 372 | exports.msToSmpte = msToSmpte; 373 | exports.secondsToFrame = secondsToFrame; 374 | exports.secondsToMedia = secondsToMedia; 375 | exports.secondsToMediaFrames = secondsToMediaFrames; 376 | exports.secondsToMs = secondsToMs; 377 | exports.secondsToSmpte = secondsToSmpte; 378 | exports.secondsToTicks = secondsToTicks; 379 | exports.seekByFrames = seekByFrames; 380 | exports.seekToFrame = seekToFrame; 381 | exports.smpteToFrame = smpteToFrame; 382 | exports.smpteToMs = smpteToMs; 383 | exports.smpteToSeconds = smpteToSeconds; 384 | exports.smpteToTicks = smpteToTicks; 385 | exports.subtractFrames = subtractFrames; 386 | exports.ticksToFrame = ticksToFrame; 387 | exports.ticksToSeconds = ticksToSeconds; 388 | exports.ticksToSmpte = ticksToSmpte; 389 | exports.toFrameTime = toFrameTime; 390 | //# sourceMappingURL=framerate-utils.cjs.development.js.map 391 | -------------------------------------------------------------------------------- /dist/framerate-utils.cjs.production.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"framerate-utils.cjs.production.min.js","sources":["../src/utils/string.ts","../src/index.ts"],"sourcesContent":["export function pad(n: number) {\n if (n < 10) {\n return `0${n.toString(10)}`;\n } else {\n return n.toString(10);\n }\n}\n\nexport function padMs(n: number) {\n if (n < 10) {\n return `00${n.toString(10)}`;\n } else if (n < 100) {\n return `0${n.toString(10)}`;\n } else {\n return n.toString(10);\n }\n}\n","import { pad, padMs } from './utils/string';\n\nconst { round, ceil, floor, max } = Math;\n\nexport const SECONDS_PER_HOUR = 60 * 60;\nexport const SECONDS_PER_MINUTE = 60;\nexport const MILLISECONDS_PER_SECOND = 1000;\nexport const TICKS_PER_SECOND = 10000000;\n\nexport const RATE_23_976 = create(24, 1000, 1001);\nexport const RATE_24 = create(24, 1, 1);\nexport const RATE_25 = create(25, 1, 1);\nexport const RATE_29_97 = create(30, 1000, 1001);\nexport const RATE_29_97_DROP = create(30, 1000, 1001, true);\nexport const RATE_30 = create(30, 1, 1);\nexport const RATE_47_95 = create(48, 1000, 1001);\nexport const RATE_48 = create(48, 1, 1);\nexport const RATE_50 = create(50, 1, 1);\nexport const RATE_59_94 = create(60, 1000, 1001);\nexport const RATE_59_94_DROP = create(60, 1000, 1001, true);\nexport const RATE_60 = create(60, 1, 1);\n\nexport const DEFAULT_FRAME_RATE = RATE_23_976;\n\n/*\n * Adjustment required to account for rounding of input data.\n * For example:\n * frame 836 @ 24fps = 34.83333333333333s\n * This can be rounded by input format to 34833ms\n * 34833ms @ 24fps is frame 835.992 which will be treated as frame 835.\n * To adjust for this 0.001s will be added before truncating.\n *\n * Update: Rounding with CAP files can cause up to 2ms difference, so update\n * rounding to up to 2ms.\n */\nexport const FRAME_ROUNDING = 0.002;\n\nexport interface FrameRate {\n rate: number;\n numerator: number;\n denominator: number;\n fps: number;\n dropFrame: boolean;\n}\n\nexport function create(\n rate = 24,\n numerator = 1,\n denominator = 1,\n dropFrame = false\n): FrameRate {\n return {\n rate,\n numerator,\n denominator,\n fps: (rate * numerator) / denominator,\n dropFrame,\n };\n}\n\nexport function secondsToSmpte(frameRate: FrameRate, seconds: number) {\n return frameToSmpte(frameRate, secondsToFrame(frameRate, seconds));\n}\n\nexport function smpteToSeconds(frameRate: FrameRate, smpte: string) {\n return frameToSeconds(frameRate, smpteToFrame(frameRate, smpte));\n}\n\nexport function smpteToMs(frameRate: FrameRate, smpte: string) {\n return ceil(smpteToSeconds(frameRate, smpte) * MILLISECONDS_PER_SECOND);\n}\n\nexport function msToSmpte(frameRate: FrameRate, ms: number) {\n return secondsToSmpte(frameRate, ms / MILLISECONDS_PER_SECOND);\n}\n\nexport function smpteToTicks(frameRate: FrameRate, smpte: string) {\n return ceil(smpteToSeconds(frameRate, smpte) * TICKS_PER_SECOND);\n}\n\nexport function ticksToSmpte(frameRate: FrameRate, ticks: number) {\n return secondsToSmpte(frameRate, ticks / TICKS_PER_SECOND);\n}\n\nexport function secondsToFrame(frameRate: FrameRate, seconds: number) {\n const frame = seconds * frameRate.fps + FRAME_ROUNDING * frameRate.fps;\n return floor(frame);\n}\n\nexport function msToFrame(frameRate: FrameRate, ms: number) {\n return secondsToFrame(frameRate, ms / MILLISECONDS_PER_SECOND);\n}\n\nexport function frameToMs(frameRate: FrameRate, frame: number) {\n return ceil(frameToSeconds(frameRate, frame) * MILLISECONDS_PER_SECOND);\n}\n\nexport function ticksToFrame(frameRate: FrameRate, ticks: number) {\n return secondsToFrame(frameRate, ticks / TICKS_PER_SECOND);\n}\n\nexport function frameToTicks(frameRate: FrameRate, frame: number) {\n return ceil(frameToSeconds(frameRate, frame) * TICKS_PER_SECOND);\n}\n\nexport function frameToSmpte(frameRate: FrameRate, frame: number) {\n const extra = extraFrames(frameRate, frame);\n const seconds = (frame + extra) / frameRate.rate;\n const f = round((seconds - floor(seconds)) * frameRate.rate);\n const h = floor(seconds / SECONDS_PER_HOUR);\n const m = floor((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);\n const s = floor(seconds % SECONDS_PER_MINUTE);\n const frameSeparator = frameRate.dropFrame ? ';' : ':';\n\n return `${pad(h)}:${pad(m)}:${pad(s)}${frameSeparator}${pad(f)}`;\n}\n\nfunction div(dividend: number, divisor: number) {\n return Math.floor(dividend / divisor);\n}\n\n/**\n * Return the number of extra frames required to convert drop frame to\n * SMPTE timecode.\n * Based on calculation from http://andrewduncan.net/timecodes/\n * D = frameNumber div 17982\n * M = frameNumber mod 17982\n * frameNumber += 18*D + 2*((M - 2) div 1798)\n * See also https://video.stackexchange.com/questions/22722/how-are-frames-in-59-94-drop-frame-timecode-dropped/22724#22724\n * for support for 59.94fps\n *\n * @param {FrameRate} frameRate The frame rate to use for conversion\n * @param {Number} frame The actual number of frames\n * @returns {Number} The extra frames required\n */\nexport function extraFrames(frameRate: FrameRate, frame: number) {\n if (!frameRate.dropFrame) {\n return 0;\n }\n\n let framesPer10Mins = 17982;\n let dropFrames = 2;\n\n if (frameRate.rate === 60) {\n framesPer10Mins = 35964;\n dropFrames = 4;\n }\n\n const D = div(frame, framesPer10Mins);\n let M = frame % framesPer10Mins;\n if (M < dropFrames) {\n // Special case for M=0 and M=1: -2 div 1798 should be 0\n M = dropFrames;\n }\n\n return max(\n 0,\n 9 * dropFrames * D +\n dropFrames * div(M - dropFrames, div(framesPer10Mins, 10))\n );\n}\n\n// Return the number of frames to subtract to convert smpte drop frame\n// back to frame number.\n// http://andrewduncan.net/timecodes/\n// totalMinutes = 60 * hours + minutes\n// frameNumber = 108000 * hours + 1800 * minutes\n// + 30 * seconds + frames\n// - 2 * (totalMinutes - totalMinutes div 10)\nexport function subtractFrames(frameRate: FrameRate, h: number, m: number) {\n if (!frameRate.dropFrame) {\n return 0;\n }\n\n let dropFrames = 2;\n\n if (frameRate.rate === 60) {\n dropFrames = 4;\n }\n\n const totalMinutes = h * 60 + m;\n\n return dropFrames * (totalMinutes - div(totalMinutes, 10));\n}\n\nexport function smpteToFrame(frameRate: FrameRate, smpte: string) {\n const parts = smpte.split(/:|;/);\n let h, m, s, f;\n\n if (parts.length === 3) {\n h = 0;\n m = parseInt(parts[0]);\n s = parseInt(parts[1]);\n f = parseInt(parts[2]);\n } else if (parts.length === 4) {\n h = parseInt(parts[0]);\n m = parseInt(parts[1]);\n s = parseInt(parts[2]);\n f = parseInt(parts[3]);\n } else {\n return 0;\n }\n\n const seconds = h * SECONDS_PER_HOUR + m * SECONDS_PER_MINUTE + s;\n const frames = seconds * frameRate.rate + f;\n\n return frames - subtractFrames(frameRate, h, m);\n}\n\nexport function frameToSeconds(frameRate: FrameRate, frame: number) {\n return frame / frameRate.fps;\n}\n\nexport function seekByFrames(\n frameRate: FrameRate,\n fromTimeSeconds: number,\n frameDelta: number\n) {\n const frame = secondsToFrame(frameRate, fromTimeSeconds);\n return seekToFrame(frameRate, frame + frameDelta);\n}\n\nexport function seekToFrame(frameRate: FrameRate, frame: number) {\n const newTime = frameToSeconds(frameRate, frame);\n const halfFrame = frameToSeconds(frameRate, 1) / 2;\n\n // add half frame to ensure the resulting time is in the frame\n return newTime + halfFrame;\n}\n\nexport function toFrameTime(frameRate: FrameRate, seconds: number) {\n return seekByFrames(frameRate, seconds, 0);\n}\n\nexport function mediaToSeconds(media: string) {\n const parts = media.split(/:|\\.|,/);\n let h, m, s, ms;\n\n if (parts.length === 4) {\n h = parseInt(parts[0]);\n m = parseInt(parts[1]);\n s = parseInt(parts[2]);\n ms = parseInt(parts[3]);\n } else {\n return 0;\n }\n\n var seconds = h * SECONDS_PER_HOUR + m * SECONDS_PER_MINUTE + s;\n return seconds + ms / 1000;\n}\n\nexport function secondsToMedia(seconds: number) {\n var milliseconds = round(seconds * MILLISECONDS_PER_SECOND);\n var sec = floor(milliseconds / MILLISECONDS_PER_SECOND);\n var ms = milliseconds % MILLISECONDS_PER_SECOND;\n var h = floor(sec / SECONDS_PER_HOUR);\n var m = floor((sec % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);\n var s = floor(sec % SECONDS_PER_MINUTE);\n\n return pad(h) + ':' + pad(m) + ':' + pad(s) + '.' + padMs(ms);\n}\n\nexport function mediaFramesToSeconds(fr: FrameRate, media: string) {\n var parts = media.split(/:/);\n let h, m, s, f;\n\n if (parts.length === 4) {\n h = parseInt(parts[0]);\n m = parseInt(parts[1]);\n s = parseInt(parts[2]);\n f = parseInt(parts[3]);\n } else {\n return 0;\n }\n\n var seconds = h * SECONDS_PER_HOUR + m * SECONDS_PER_MINUTE + s;\n return seconds + f / fr.fps;\n}\n\nexport function secondsToMediaFrames(fr: FrameRate, seconds: number) {\n var sec = floor(seconds);\n var f = round((seconds - sec) * fr.fps);\n var h = floor(sec / SECONDS_PER_HOUR);\n var m = floor((sec % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);\n var s = floor(sec % SECONDS_PER_MINUTE);\n\n return pad(h) + ':' + pad(m) + ':' + pad(s) + ':' + pad(f);\n}\n\nexport function ticksToSeconds(ticks: number) {\n return ticks / TICKS_PER_SECOND;\n}\n\nexport function secondsToTicks(seconds: number) {\n return floor(seconds * TICKS_PER_SECOND);\n}\n\nexport function msToSeconds(ms: number) {\n return ms / MILLISECONDS_PER_SECOND;\n}\n\nexport function secondsToMs(seconds: number) {\n return seconds * MILLISECONDS_PER_SECOND;\n}\n\nexport function fromTag(tag: string) {\n switch (tag) {\n case 'FPS_2397':\n return RATE_23_976;\n case 'FPS_24':\n return RATE_24;\n case 'FPS_2400':\n return RATE_24;\n case 'FPS_25':\n return RATE_25;\n case 'FPS_2500':\n return RATE_25;\n case 'FPS_2997':\n return RATE_29_97_DROP;\n case 'FPS_30':\n return RATE_30;\n case 'FPS_3000':\n return RATE_30;\n case 'FPS_4795':\n return RATE_47_95;\n case 'FPS_48':\n return RATE_48;\n case 'FPS_4800':\n return RATE_48;\n case 'FPS_50':\n return RATE_50;\n case 'FPS_5000':\n return RATE_50;\n case 'FPS_5994':\n return RATE_59_94_DROP;\n case 'FPS_60':\n return RATE_60;\n case 'FPS_6000':\n return RATE_60;\n default:\n throw new TypeError(`Unknown Frame Rate ${tag}`);\n }\n}\n"],"names":["pad","n","toString","round","Math","ceil","floor","max","RATE_23_976","create","RATE_24","RATE_25","RATE_29_97","RATE_29_97_DROP","RATE_30","RATE_47_95","RATE_48","RATE_50","RATE_59_94","RATE_59_94_DROP","RATE_60","rate","numerator","denominator","dropFrame","fps","secondsToSmpte","frameRate","seconds","frameToSmpte","secondsToFrame","smpteToSeconds","smpte","frameToSeconds","smpteToFrame","frame","extraFrames","f","h","m","s","frameSeparator","div","dividend","divisor","framesPer10Mins","dropFrames","D","M","subtractFrames","totalMinutes","parts","split","length","parseInt","seekByFrames","fromTimeSeconds","frameDelta","seekToFrame","tag","TypeError","fr","media","ms","milliseconds","sec","ticks"],"mappings":"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"} -------------------------------------------------------------------------------- /dist/framerate-utils.esm.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"framerate-utils.esm.js","sources":["../src/utils/string.ts","../src/index.ts"],"sourcesContent":["export function pad(n: number) {\n if (n < 10) {\n return `0${n.toString(10)}`;\n } else {\n return n.toString(10);\n }\n}\n\nexport function padMs(n: number) {\n if (n < 10) {\n return `00${n.toString(10)}`;\n } else if (n < 100) {\n return `0${n.toString(10)}`;\n } else {\n return n.toString(10);\n }\n}\n","import { pad, padMs } from './utils/string';\n\nconst { round, ceil, floor, max } = Math;\n\nexport const SECONDS_PER_HOUR = 60 * 60;\nexport const SECONDS_PER_MINUTE = 60;\nexport const MILLISECONDS_PER_SECOND = 1000;\nexport const TICKS_PER_SECOND = 10000000;\n\nexport const RATE_23_976 = create(24, 1000, 1001);\nexport const RATE_24 = create(24, 1, 1);\nexport const RATE_25 = create(25, 1, 1);\nexport const RATE_29_97 = create(30, 1000, 1001);\nexport const RATE_29_97_DROP = create(30, 1000, 1001, true);\nexport const RATE_30 = create(30, 1, 1);\nexport const RATE_47_95 = create(48, 1000, 1001);\nexport const RATE_48 = create(48, 1, 1);\nexport const RATE_50 = create(50, 1, 1);\nexport const RATE_59_94 = create(60, 1000, 1001);\nexport const RATE_59_94_DROP = create(60, 1000, 1001, true);\nexport const RATE_60 = create(60, 1, 1);\n\nexport const DEFAULT_FRAME_RATE = RATE_23_976;\n\n/*\n * Adjustment required to account for rounding of input data.\n * For example:\n * frame 836 @ 24fps = 34.83333333333333s\n * This can be rounded by input format to 34833ms\n * 34833ms @ 24fps is frame 835.992 which will be treated as frame 835.\n * To adjust for this 0.001s will be added before truncating.\n *\n * Update: Rounding with CAP files can cause up to 2ms difference, so update\n * rounding to up to 2ms.\n */\nexport const FRAME_ROUNDING = 0.002;\n\nexport interface FrameRate {\n rate: number;\n numerator: number;\n denominator: number;\n fps: number;\n dropFrame: boolean;\n}\n\nexport function create(\n rate = 24,\n numerator = 1,\n denominator = 1,\n dropFrame = false\n): FrameRate {\n return {\n rate,\n numerator,\n denominator,\n fps: (rate * numerator) / denominator,\n dropFrame,\n };\n}\n\nexport function secondsToSmpte(frameRate: FrameRate, seconds: number) {\n return frameToSmpte(frameRate, secondsToFrame(frameRate, seconds));\n}\n\nexport function smpteToSeconds(frameRate: FrameRate, smpte: string) {\n return frameToSeconds(frameRate, smpteToFrame(frameRate, smpte));\n}\n\nexport function smpteToMs(frameRate: FrameRate, smpte: string) {\n return ceil(smpteToSeconds(frameRate, smpte) * MILLISECONDS_PER_SECOND);\n}\n\nexport function msToSmpte(frameRate: FrameRate, ms: number) {\n return secondsToSmpte(frameRate, ms / MILLISECONDS_PER_SECOND);\n}\n\nexport function smpteToTicks(frameRate: FrameRate, smpte: string) {\n return ceil(smpteToSeconds(frameRate, smpte) * TICKS_PER_SECOND);\n}\n\nexport function ticksToSmpte(frameRate: FrameRate, ticks: number) {\n return secondsToSmpte(frameRate, ticks / TICKS_PER_SECOND);\n}\n\nexport function secondsToFrame(frameRate: FrameRate, seconds: number) {\n const frame = seconds * frameRate.fps + FRAME_ROUNDING * frameRate.fps;\n return floor(frame);\n}\n\nexport function msToFrame(frameRate: FrameRate, ms: number) {\n return secondsToFrame(frameRate, ms / MILLISECONDS_PER_SECOND);\n}\n\nexport function frameToMs(frameRate: FrameRate, frame: number) {\n return ceil(frameToSeconds(frameRate, frame) * MILLISECONDS_PER_SECOND);\n}\n\nexport function ticksToFrame(frameRate: FrameRate, ticks: number) {\n return secondsToFrame(frameRate, ticks / TICKS_PER_SECOND);\n}\n\nexport function frameToTicks(frameRate: FrameRate, frame: number) {\n return ceil(frameToSeconds(frameRate, frame) * TICKS_PER_SECOND);\n}\n\nexport function frameToSmpte(frameRate: FrameRate, frame: number) {\n const extra = extraFrames(frameRate, frame);\n const seconds = (frame + extra) / frameRate.rate;\n const f = round((seconds - floor(seconds)) * frameRate.rate);\n const h = floor(seconds / SECONDS_PER_HOUR);\n const m = floor((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);\n const s = floor(seconds % SECONDS_PER_MINUTE);\n const frameSeparator = frameRate.dropFrame ? ';' : ':';\n\n return `${pad(h)}:${pad(m)}:${pad(s)}${frameSeparator}${pad(f)}`;\n}\n\nfunction div(dividend: number, divisor: number) {\n return Math.floor(dividend / divisor);\n}\n\n/**\n * Return the number of extra frames required to convert drop frame to\n * SMPTE timecode.\n * Based on calculation from http://andrewduncan.net/timecodes/\n * D = frameNumber div 17982\n * M = frameNumber mod 17982\n * frameNumber += 18*D + 2*((M - 2) div 1798)\n * See also https://video.stackexchange.com/questions/22722/how-are-frames-in-59-94-drop-frame-timecode-dropped/22724#22724\n * for support for 59.94fps\n *\n * @param {FrameRate} frameRate The frame rate to use for conversion\n * @param {Number} frame The actual number of frames\n * @returns {Number} The extra frames required\n */\nexport function extraFrames(frameRate: FrameRate, frame: number) {\n if (!frameRate.dropFrame) {\n return 0;\n }\n\n let framesPer10Mins = 17982;\n let dropFrames = 2;\n\n if (frameRate.rate === 60) {\n framesPer10Mins = 35964;\n dropFrames = 4;\n }\n\n const D = div(frame, framesPer10Mins);\n let M = frame % framesPer10Mins;\n if (M < dropFrames) {\n // Special case for M=0 and M=1: -2 div 1798 should be 0\n M = dropFrames;\n }\n\n return max(\n 0,\n 9 * dropFrames * D +\n dropFrames * div(M - dropFrames, div(framesPer10Mins, 10))\n );\n}\n\n// Return the number of frames to subtract to convert smpte drop frame\n// back to frame number.\n// http://andrewduncan.net/timecodes/\n// totalMinutes = 60 * hours + minutes\n// frameNumber = 108000 * hours + 1800 * minutes\n// + 30 * seconds + frames\n// - 2 * (totalMinutes - totalMinutes div 10)\nexport function subtractFrames(frameRate: FrameRate, h: number, m: number) {\n if (!frameRate.dropFrame) {\n return 0;\n }\n\n let dropFrames = 2;\n\n if (frameRate.rate === 60) {\n dropFrames = 4;\n }\n\n const totalMinutes = h * 60 + m;\n\n return dropFrames * (totalMinutes - div(totalMinutes, 10));\n}\n\nexport function smpteToFrame(frameRate: FrameRate, smpte: string) {\n const parts = smpte.split(/:|;/);\n let h, m, s, f;\n\n if (parts.length === 3) {\n h = 0;\n m = parseInt(parts[0]);\n s = parseInt(parts[1]);\n f = parseInt(parts[2]);\n } else if (parts.length === 4) {\n h = parseInt(parts[0]);\n m = parseInt(parts[1]);\n s = parseInt(parts[2]);\n f = parseInt(parts[3]);\n } else {\n return 0;\n }\n\n const seconds = h * SECONDS_PER_HOUR + m * SECONDS_PER_MINUTE + s;\n const frames = seconds * frameRate.rate + f;\n\n return frames - subtractFrames(frameRate, h, m);\n}\n\nexport function frameToSeconds(frameRate: FrameRate, frame: number) {\n return frame / frameRate.fps;\n}\n\nexport function seekByFrames(\n frameRate: FrameRate,\n fromTimeSeconds: number,\n frameDelta: number\n) {\n const frame = secondsToFrame(frameRate, fromTimeSeconds);\n return seekToFrame(frameRate, frame + frameDelta);\n}\n\nexport function seekToFrame(frameRate: FrameRate, frame: number) {\n const newTime = frameToSeconds(frameRate, frame);\n const halfFrame = frameToSeconds(frameRate, 1) / 2;\n\n // add half frame to ensure the resulting time is in the frame\n return newTime + halfFrame;\n}\n\nexport function toFrameTime(frameRate: FrameRate, seconds: number) {\n return seekByFrames(frameRate, seconds, 0);\n}\n\nexport function mediaToSeconds(media: string) {\n const parts = media.split(/:|\\.|,/);\n let h, m, s, ms;\n\n if (parts.length === 4) {\n h = parseInt(parts[0]);\n m = parseInt(parts[1]);\n s = parseInt(parts[2]);\n ms = parseInt(parts[3]);\n } else {\n return 0;\n }\n\n var seconds = h * SECONDS_PER_HOUR + m * SECONDS_PER_MINUTE + s;\n return seconds + ms / 1000;\n}\n\nexport function secondsToMedia(seconds: number) {\n var milliseconds = round(seconds * MILLISECONDS_PER_SECOND);\n var sec = floor(milliseconds / MILLISECONDS_PER_SECOND);\n var ms = milliseconds % MILLISECONDS_PER_SECOND;\n var h = floor(sec / SECONDS_PER_HOUR);\n var m = floor((sec % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);\n var s = floor(sec % SECONDS_PER_MINUTE);\n\n return pad(h) + ':' + pad(m) + ':' + pad(s) + '.' + padMs(ms);\n}\n\nexport function mediaFramesToSeconds(fr: FrameRate, media: string) {\n var parts = media.split(/:/);\n let h, m, s, f;\n\n if (parts.length === 4) {\n h = parseInt(parts[0]);\n m = parseInt(parts[1]);\n s = parseInt(parts[2]);\n f = parseInt(parts[3]);\n } else {\n return 0;\n }\n\n var seconds = h * SECONDS_PER_HOUR + m * SECONDS_PER_MINUTE + s;\n return seconds + f / fr.fps;\n}\n\nexport function secondsToMediaFrames(fr: FrameRate, seconds: number) {\n var sec = floor(seconds);\n var f = round((seconds - sec) * fr.fps);\n var h = floor(sec / SECONDS_PER_HOUR);\n var m = floor((sec % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);\n var s = floor(sec % SECONDS_PER_MINUTE);\n\n return pad(h) + ':' + pad(m) + ':' + pad(s) + ':' + pad(f);\n}\n\nexport function ticksToSeconds(ticks: number) {\n return ticks / TICKS_PER_SECOND;\n}\n\nexport function secondsToTicks(seconds: number) {\n return floor(seconds * TICKS_PER_SECOND);\n}\n\nexport function msToSeconds(ms: number) {\n return ms / MILLISECONDS_PER_SECOND;\n}\n\nexport function secondsToMs(seconds: number) {\n return seconds * MILLISECONDS_PER_SECOND;\n}\n\nexport function fromTag(tag: string) {\n switch (tag) {\n case 'FPS_2397':\n return RATE_23_976;\n case 'FPS_24':\n return RATE_24;\n case 'FPS_2400':\n return RATE_24;\n case 'FPS_25':\n return RATE_25;\n case 'FPS_2500':\n return RATE_25;\n case 'FPS_2997':\n return RATE_29_97_DROP;\n case 'FPS_30':\n return RATE_30;\n case 'FPS_3000':\n return RATE_30;\n case 'FPS_4795':\n return RATE_47_95;\n case 'FPS_48':\n return RATE_48;\n case 'FPS_4800':\n return RATE_48;\n case 'FPS_50':\n return RATE_50;\n case 'FPS_5000':\n return RATE_50;\n case 'FPS_5994':\n return RATE_59_94_DROP;\n case 'FPS_60':\n return RATE_60;\n case 'FPS_6000':\n return RATE_60;\n default:\n throw new TypeError(`Unknown Frame Rate ${tag}`);\n }\n}\n"],"names":["pad","n","toString","padMs","round","Math","ceil","floor","max","SECONDS_PER_HOUR","SECONDS_PER_MINUTE","MILLISECONDS_PER_SECOND","TICKS_PER_SECOND","RATE_23_976","create","RATE_24","RATE_25","RATE_29_97","RATE_29_97_DROP","RATE_30","RATE_47_95","RATE_48","RATE_50","RATE_59_94","RATE_59_94_DROP","RATE_60","DEFAULT_FRAME_RATE","FRAME_ROUNDING","rate","numerator","denominator","dropFrame","fps","secondsToSmpte","frameRate","seconds","frameToSmpte","secondsToFrame","smpteToSeconds","smpte","frameToSeconds","smpteToFrame","smpteToMs","msToSmpte","ms","smpteToTicks","ticksToSmpte","ticks","frame","msToFrame","frameToMs","ticksToFrame","frameToTicks","extra","extraFrames","f","h","m","s","frameSeparator","div","dividend","divisor","framesPer10Mins","dropFrames","D","M","subtractFrames","totalMinutes","parts","split","length","parseInt","frames","seekByFrames","fromTimeSeconds","frameDelta","seekToFrame","newTime","halfFrame","toFrameTime","mediaToSeconds","media","secondsToMedia","milliseconds","sec","mediaFramesToSeconds","fr","secondsToMediaFrames","ticksToSeconds","secondsToTicks","msToSeconds","secondsToMs","fromTag","tag","TypeError"],"mappings":"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"} -------------------------------------------------------------------------------- /dist/framerate-utils.cjs.development.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"framerate-utils.cjs.development.js","sources":["../src/utils/string.ts","../src/index.ts"],"sourcesContent":["export function pad(n: number) {\n if (n < 10) {\n return `0${n.toString(10)}`;\n } else {\n return n.toString(10);\n }\n}\n\nexport function padMs(n: number) {\n if (n < 10) {\n return `00${n.toString(10)}`;\n } else if (n < 100) {\n return `0${n.toString(10)}`;\n } else {\n return n.toString(10);\n }\n}\n","import { pad, padMs } from './utils/string';\n\nconst { round, ceil, floor, max } = Math;\n\nexport const SECONDS_PER_HOUR = 60 * 60;\nexport const SECONDS_PER_MINUTE = 60;\nexport const MILLISECONDS_PER_SECOND = 1000;\nexport const TICKS_PER_SECOND = 10000000;\n\nexport const RATE_23_976 = create(24, 1000, 1001);\nexport const RATE_24 = create(24, 1, 1);\nexport const RATE_25 = create(25, 1, 1);\nexport const RATE_29_97 = create(30, 1000, 1001);\nexport const RATE_29_97_DROP = create(30, 1000, 1001, true);\nexport const RATE_30 = create(30, 1, 1);\nexport const RATE_47_95 = create(48, 1000, 1001);\nexport const RATE_48 = create(48, 1, 1);\nexport const RATE_50 = create(50, 1, 1);\nexport const RATE_59_94 = create(60, 1000, 1001);\nexport const RATE_59_94_DROP = create(60, 1000, 1001, true);\nexport const RATE_60 = create(60, 1, 1);\n\nexport const DEFAULT_FRAME_RATE = RATE_23_976;\n\n/*\n * Adjustment required to account for rounding of input data.\n * For example:\n * frame 836 @ 24fps = 34.83333333333333s\n * This can be rounded by input format to 34833ms\n * 34833ms @ 24fps is frame 835.992 which will be treated as frame 835.\n * To adjust for this 0.001s will be added before truncating.\n *\n * Update: Rounding with CAP files can cause up to 2ms difference, so update\n * rounding to up to 2ms.\n */\nexport const FRAME_ROUNDING = 0.002;\n\nexport interface FrameRate {\n rate: number;\n numerator: number;\n denominator: number;\n fps: number;\n dropFrame: boolean;\n}\n\nexport function create(\n rate = 24,\n numerator = 1,\n denominator = 1,\n dropFrame = false\n): FrameRate {\n return {\n rate,\n numerator,\n denominator,\n fps: (rate * numerator) / denominator,\n dropFrame,\n };\n}\n\nexport function secondsToSmpte(frameRate: FrameRate, seconds: number) {\n return frameToSmpte(frameRate, secondsToFrame(frameRate, seconds));\n}\n\nexport function smpteToSeconds(frameRate: FrameRate, smpte: string) {\n return frameToSeconds(frameRate, smpteToFrame(frameRate, smpte));\n}\n\nexport function smpteToMs(frameRate: FrameRate, smpte: string) {\n return ceil(smpteToSeconds(frameRate, smpte) * MILLISECONDS_PER_SECOND);\n}\n\nexport function msToSmpte(frameRate: FrameRate, ms: number) {\n return secondsToSmpte(frameRate, ms / MILLISECONDS_PER_SECOND);\n}\n\nexport function smpteToTicks(frameRate: FrameRate, smpte: string) {\n return ceil(smpteToSeconds(frameRate, smpte) * TICKS_PER_SECOND);\n}\n\nexport function ticksToSmpte(frameRate: FrameRate, ticks: number) {\n return secondsToSmpte(frameRate, ticks / TICKS_PER_SECOND);\n}\n\nexport function secondsToFrame(frameRate: FrameRate, seconds: number) {\n const frame = seconds * frameRate.fps + FRAME_ROUNDING * frameRate.fps;\n return floor(frame);\n}\n\nexport function msToFrame(frameRate: FrameRate, ms: number) {\n return secondsToFrame(frameRate, ms / MILLISECONDS_PER_SECOND);\n}\n\nexport function frameToMs(frameRate: FrameRate, frame: number) {\n return ceil(frameToSeconds(frameRate, frame) * MILLISECONDS_PER_SECOND);\n}\n\nexport function ticksToFrame(frameRate: FrameRate, ticks: number) {\n return secondsToFrame(frameRate, ticks / TICKS_PER_SECOND);\n}\n\nexport function frameToTicks(frameRate: FrameRate, frame: number) {\n return ceil(frameToSeconds(frameRate, frame) * TICKS_PER_SECOND);\n}\n\nexport function frameToSmpte(frameRate: FrameRate, frame: number) {\n const extra = extraFrames(frameRate, frame);\n const seconds = (frame + extra) / frameRate.rate;\n const f = round((seconds - floor(seconds)) * frameRate.rate);\n const h = floor(seconds / SECONDS_PER_HOUR);\n const m = floor((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);\n const s = floor(seconds % SECONDS_PER_MINUTE);\n const frameSeparator = frameRate.dropFrame ? ';' : ':';\n\n return `${pad(h)}:${pad(m)}:${pad(s)}${frameSeparator}${pad(f)}`;\n}\n\nfunction div(dividend: number, divisor: number) {\n return Math.floor(dividend / divisor);\n}\n\n/**\n * Return the number of extra frames required to convert drop frame to\n * SMPTE timecode.\n * Based on calculation from http://andrewduncan.net/timecodes/\n * D = frameNumber div 17982\n * M = frameNumber mod 17982\n * frameNumber += 18*D + 2*((M - 2) div 1798)\n * See also https://video.stackexchange.com/questions/22722/how-are-frames-in-59-94-drop-frame-timecode-dropped/22724#22724\n * for support for 59.94fps\n *\n * @param {FrameRate} frameRate The frame rate to use for conversion\n * @param {Number} frame The actual number of frames\n * @returns {Number} The extra frames required\n */\nexport function extraFrames(frameRate: FrameRate, frame: number) {\n if (!frameRate.dropFrame) {\n return 0;\n }\n\n let framesPer10Mins = 17982;\n let dropFrames = 2;\n\n if (frameRate.rate === 60) {\n framesPer10Mins = 35964;\n dropFrames = 4;\n }\n\n const D = div(frame, framesPer10Mins);\n let M = frame % framesPer10Mins;\n if (M < dropFrames) {\n // Special case for M=0 and M=1: -2 div 1798 should be 0\n M = dropFrames;\n }\n\n return max(\n 0,\n 9 * dropFrames * D +\n dropFrames * div(M - dropFrames, div(framesPer10Mins, 10))\n );\n}\n\n// Return the number of frames to subtract to convert smpte drop frame\n// back to frame number.\n// http://andrewduncan.net/timecodes/\n// totalMinutes = 60 * hours + minutes\n// frameNumber = 108000 * hours + 1800 * minutes\n// + 30 * seconds + frames\n// - 2 * (totalMinutes - totalMinutes div 10)\nexport function subtractFrames(frameRate: FrameRate, h: number, m: number) {\n if (!frameRate.dropFrame) {\n return 0;\n }\n\n let dropFrames = 2;\n\n if (frameRate.rate === 60) {\n dropFrames = 4;\n }\n\n const totalMinutes = h * 60 + m;\n\n return dropFrames * (totalMinutes - div(totalMinutes, 10));\n}\n\nexport function smpteToFrame(frameRate: FrameRate, smpte: string) {\n const parts = smpte.split(/:|;/);\n let h, m, s, f;\n\n if (parts.length === 3) {\n h = 0;\n m = parseInt(parts[0]);\n s = parseInt(parts[1]);\n f = parseInt(parts[2]);\n } else if (parts.length === 4) {\n h = parseInt(parts[0]);\n m = parseInt(parts[1]);\n s = parseInt(parts[2]);\n f = parseInt(parts[3]);\n } else {\n return 0;\n }\n\n const seconds = h * SECONDS_PER_HOUR + m * SECONDS_PER_MINUTE + s;\n const frames = seconds * frameRate.rate + f;\n\n return frames - subtractFrames(frameRate, h, m);\n}\n\nexport function frameToSeconds(frameRate: FrameRate, frame: number) {\n return frame / frameRate.fps;\n}\n\nexport function seekByFrames(\n frameRate: FrameRate,\n fromTimeSeconds: number,\n frameDelta: number\n) {\n const frame = secondsToFrame(frameRate, fromTimeSeconds);\n return seekToFrame(frameRate, frame + frameDelta);\n}\n\nexport function seekToFrame(frameRate: FrameRate, frame: number) {\n const newTime = frameToSeconds(frameRate, frame);\n const halfFrame = frameToSeconds(frameRate, 1) / 2;\n\n // add half frame to ensure the resulting time is in the frame\n return newTime + halfFrame;\n}\n\nexport function toFrameTime(frameRate: FrameRate, seconds: number) {\n return seekByFrames(frameRate, seconds, 0);\n}\n\nexport function mediaToSeconds(media: string) {\n const parts = media.split(/:|\\.|,/);\n let h, m, s, ms;\n\n if (parts.length === 4) {\n h = parseInt(parts[0]);\n m = parseInt(parts[1]);\n s = parseInt(parts[2]);\n ms = parseInt(parts[3]);\n } else {\n return 0;\n }\n\n var seconds = h * SECONDS_PER_HOUR + m * SECONDS_PER_MINUTE + s;\n return seconds + ms / 1000;\n}\n\nexport function secondsToMedia(seconds: number) {\n var milliseconds = round(seconds * MILLISECONDS_PER_SECOND);\n var sec = floor(milliseconds / MILLISECONDS_PER_SECOND);\n var ms = milliseconds % MILLISECONDS_PER_SECOND;\n var h = floor(sec / SECONDS_PER_HOUR);\n var m = floor((sec % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);\n var s = floor(sec % SECONDS_PER_MINUTE);\n\n return pad(h) + ':' + pad(m) + ':' + pad(s) + '.' + padMs(ms);\n}\n\nexport function mediaFramesToSeconds(fr: FrameRate, media: string) {\n var parts = media.split(/:/);\n let h, m, s, f;\n\n if (parts.length === 4) {\n h = parseInt(parts[0]);\n m = parseInt(parts[1]);\n s = parseInt(parts[2]);\n f = parseInt(parts[3]);\n } else {\n return 0;\n }\n\n var seconds = h * SECONDS_PER_HOUR + m * SECONDS_PER_MINUTE + s;\n return seconds + f / fr.fps;\n}\n\nexport function secondsToMediaFrames(fr: FrameRate, seconds: number) {\n var sec = floor(seconds);\n var f = round((seconds - sec) * fr.fps);\n var h = floor(sec / SECONDS_PER_HOUR);\n var m = floor((sec % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);\n var s = floor(sec % SECONDS_PER_MINUTE);\n\n return pad(h) + ':' + pad(m) + ':' + pad(s) + ':' + pad(f);\n}\n\nexport function ticksToSeconds(ticks: number) {\n return ticks / TICKS_PER_SECOND;\n}\n\nexport function secondsToTicks(seconds: number) {\n return floor(seconds * TICKS_PER_SECOND);\n}\n\nexport function msToSeconds(ms: number) {\n return ms / MILLISECONDS_PER_SECOND;\n}\n\nexport function secondsToMs(seconds: number) {\n return seconds * MILLISECONDS_PER_SECOND;\n}\n\nexport function fromTag(tag: string) {\n switch (tag) {\n case 'FPS_2397':\n return RATE_23_976;\n case 'FPS_24':\n return RATE_24;\n case 'FPS_2400':\n return RATE_24;\n case 'FPS_25':\n return RATE_25;\n case 'FPS_2500':\n return RATE_25;\n case 'FPS_2997':\n return RATE_29_97_DROP;\n case 'FPS_30':\n return RATE_30;\n case 'FPS_3000':\n return RATE_30;\n case 'FPS_4795':\n return RATE_47_95;\n case 'FPS_48':\n return RATE_48;\n case 'FPS_4800':\n return RATE_48;\n case 'FPS_50':\n return RATE_50;\n case 'FPS_5000':\n return RATE_50;\n case 'FPS_5994':\n return RATE_59_94_DROP;\n case 'FPS_60':\n return RATE_60;\n case 'FPS_6000':\n return RATE_60;\n default:\n throw new TypeError(`Unknown Frame Rate ${tag}`);\n }\n}\n"],"names":["pad","n","toString","padMs","round","Math","ceil","floor","max","SECONDS_PER_HOUR","SECONDS_PER_MINUTE","MILLISECONDS_PER_SECOND","TICKS_PER_SECOND","RATE_23_976","create","RATE_24","RATE_25","RATE_29_97","RATE_29_97_DROP","RATE_30","RATE_47_95","RATE_48","RATE_50","RATE_59_94","RATE_59_94_DROP","RATE_60","DEFAULT_FRAME_RATE","FRAME_ROUNDING","rate","numerator","denominator","dropFrame","fps","secondsToSmpte","frameRate","seconds","frameToSmpte","secondsToFrame","smpteToSeconds","smpte","frameToSeconds","smpteToFrame","smpteToMs","msToSmpte","ms","smpteToTicks","ticksToSmpte","ticks","frame","msToFrame","frameToMs","ticksToFrame","frameToTicks","extra","extraFrames","f","h","m","s","frameSeparator","div","dividend","divisor","framesPer10Mins","dropFrames","D","M","subtractFrames","totalMinutes","parts","split","length","parseInt","frames","seekByFrames","fromTimeSeconds","frameDelta","seekToFrame","newTime","halfFrame","toFrameTime","mediaToSeconds","media","secondsToMedia","milliseconds","sec","mediaFramesToSeconds","fr","secondsToMediaFrames","ticksToSeconds","secondsToTicks","msToSeconds","secondsToMs","fromTag","tag","TypeError"],"mappings":"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"} --------------------------------------------------------------------------------