import { clContext as nodenCLContext , OpenCLBuffer } from 'nodencl' ; import { ClJobs } from '../clJobQueue' ; import ImageProcess from './imageProcess' ; import YadifCl from './yadifCl' ; export type YadifMode = 'send_frame' | 'send_field' | 'send_frame_nospatial' | 'send_field_nospatial' ; export type YadifConfig = { mode : YadifMode ; tff : boolean ; } ; export default class Yadif { private readonly clContext : nodenCLContext ; private readonly clJobs : ClJobs ; private readonly width : number ; private readonly height : number ; private readonly config : YadifConfig ; private readonly interlaced : boolean ; private readonly sendField : boolean ; private readonly skipSpatial : boolean ; private yadifCl : ImageProcess | null = null ; private in : OpenCLBuffer [ ] = [ ] ; private out : OpenCLBuffer | null = null ; constructor ( clContext , clJobs , width , height , config , interlaced ) { this . clContext = clContext ; this . clJobs = clJobs ; this . width = width ; this . height = height ; this . config = config ; this . interlaced = interlaced ; this . sendField = this . interlaced && ( this . config . mode === 'send_field' || this . config . mode === 'send_field_nospatial' ) ; this . skipSpatial = this . config . mode === 'send_frame_nospatial' || this . config . mode === 'send_field_nospatial' ; } async init ( ) { this . yadifCl = new ImageProcess ( this . clContext , new YadifCl ( this . width , this . height ) , this . clJobs ) ; await this . yadifCl . init ( ) ; } private async makeOutput ( isSecond ) { const numBytesRGBA = this . width * this . height * 4 * 4 ; this . out = await this . clContext . createBuffer ( numBytesRGBA , 'readwrite' , 'coarse' , { width : this . width , height : this . height } , `yadif ${ isSecond ? '2' : '1' }` ) ; } private async runYadif ( isSecond , sourceID ) { if ( ! this . yadifCl ) throw new Error ( 'Yadif needs to be initialised' ) ; const srcs = this . in . slice ( 0 ) ; srcs . forEach ( ( s ) => s . addRef ( ) ) ; const out = this . out as OpenCLBuffer ; out . timestamp = srcs [ 1 ] . timestamp + ( isSecond ? 1 : 0 ) ; await this . yadifCl . run ( { prev : srcs [ 0 ] , cur : srcs [ 1 ] , next : srcs [ 2 ] , parity : ( this . config . tff ? 1 : 0 ) ^ ( ! isSecond ? 1 : 0 ) , tff : this . config . tff , skipSpatial : this . skipSpatial , output : out } , { source : sourceID , timestamp : out . timestamp } , ( ) => srcs . forEach ( ( s ) => s . release ( ) ) ) ; await this . clJobs . runQueue ( { source : sourceID , timestamp : out . timestamp } ) ; } async processFrame ( input , outputs , sourceID ) { if ( ! this . interlaced ) { outputs . push ( input ) ; return ; } this . in . push ( input ) ; if ( this . in . length < 3 ) { await this . clJobs . runQueue ( { source : sourceID , timestamp : input . timestamp } ) ; return ; } if ( this . in . length > 3 ) { const old = this . in . shift ( ) ; old ?. release ( ) ; } await this . makeOutput ( false ) ; await this . runYadif ( false , sourceID ) ; outputs . push ( this . out as OpenCLBuffer ) ; if ( this . sendField ) { await this . makeOutput ( true ) ; await this . runYadif ( true , sourceID ) ; outputs . push ( this . out as OpenCLBuffer ) ; } } release ( ) { this . in . forEach ( ( i ) => i . release ( ) ) ; } }