forked from Cutlery/immich
		
	feat(server): easy RKMPP video encoding (#7460)
* feat(server): easy RKMPP video encoding * make linter happy
This commit is contained in:
		
							parent
							
								
									cfb49c8be0
								
							
						
					
					
						commit
						5e485e35e9
					
				@ -38,12 +38,6 @@ services:
 | 
				
			|||||||
      - /dev/dri:/dev/dri
 | 
					      - /dev/dri:/dev/dri
 | 
				
			||||||
      - /dev/dma_heap:/dev/dma_heap
 | 
					      - /dev/dma_heap:/dev/dma_heap
 | 
				
			||||||
      - /dev/mpp_service:/dev/mpp_service
 | 
					      - /dev/mpp_service:/dev/mpp_service
 | 
				
			||||||
    volumes:
 | 
					 | 
				
			||||||
      - /usr/bin/ffmpeg:/usr/bin/ffmpeg_mpp:ro
 | 
					 | 
				
			||||||
      - /lib/aarch64-linux-gnu:/lib/ffmpeg-mpp:ro
 | 
					 | 
				
			||||||
      - /lib/aarch64-linux-gnu/libblas.so.3:/lib/ffmpeg-mpp/libblas.so.3:ro # symlink is resolved by mounting
 | 
					 | 
				
			||||||
      - /lib/aarch64-linux-gnu/liblapack.so.3:/lib/ffmpeg-mpp/liblapack.so.3:ro # symlink is resolved by mounting
 | 
					 | 
				
			||||||
      - /lib/aarch64-linux-gnu/pulseaudio/libpulsecommon-15.99.so:/lib/ffmpeg-mpp/libpulsecommon-15.99.so:ro
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  vaapi:
 | 
					  vaapi:
 | 
				
			||||||
    devices:
 | 
					    devices:
 | 
				
			||||||
 | 
				
			|||||||
@ -1801,7 +1801,7 @@ describe(MediaService.name, () => {
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
          inputOptions: [],
 | 
					          inputOptions: [],
 | 
				
			||||||
          outputOptions: [
 | 
					          outputOptions: [
 | 
				
			||||||
            `-c:v hevc_rkmpp_encoder`,
 | 
					            `-c:v hevc_rkmpp`,
 | 
				
			||||||
            '-c:a copy',
 | 
					            '-c:a copy',
 | 
				
			||||||
            '-movflags faststart',
 | 
					            '-movflags faststart',
 | 
				
			||||||
            '-fps_mode passthrough',
 | 
					            '-fps_mode passthrough',
 | 
				
			||||||
@ -1810,17 +1810,12 @@ describe(MediaService.name, () => {
 | 
				
			|||||||
            '-g 256',
 | 
					            '-g 256',
 | 
				
			||||||
            '-tag:v hvc1',
 | 
					            '-tag:v hvc1',
 | 
				
			||||||
            '-v verbose',
 | 
					            '-v verbose',
 | 
				
			||||||
 | 
					            '-vf scale=-2:720,format=yuv420p',
 | 
				
			||||||
            '-level 153',
 | 
					            '-level 153',
 | 
				
			||||||
            '-rc_mode 3',
 | 
					            '-rc_mode 3',
 | 
				
			||||||
            '-quality_min 0',
 | 
					 | 
				
			||||||
            '-quality_max 100',
 | 
					 | 
				
			||||||
            '-b:v 10000k',
 | 
					            '-b:v 10000k',
 | 
				
			||||||
            '-width 1280',
 | 
					 | 
				
			||||||
            '-height 720',
 | 
					 | 
				
			||||||
          ],
 | 
					          ],
 | 
				
			||||||
          twoPass: false,
 | 
					          twoPass: false,
 | 
				
			||||||
          ffmpegPath: 'ffmpeg_mpp',
 | 
					 | 
				
			||||||
          ldLibraryPath: '/lib/aarch64-linux-gnu:/lib/ffmpeg-mpp',
 | 
					 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@ -1841,7 +1836,7 @@ describe(MediaService.name, () => {
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
          inputOptions: [],
 | 
					          inputOptions: [],
 | 
				
			||||||
          outputOptions: [
 | 
					          outputOptions: [
 | 
				
			||||||
            `-c:v h264_rkmpp_encoder`,
 | 
					            `-c:v h264_rkmpp`,
 | 
				
			||||||
            '-c:a copy',
 | 
					            '-c:a copy',
 | 
				
			||||||
            '-movflags faststart',
 | 
					            '-movflags faststart',
 | 
				
			||||||
            '-fps_mode passthrough',
 | 
					            '-fps_mode passthrough',
 | 
				
			||||||
@ -1849,16 +1844,12 @@ describe(MediaService.name, () => {
 | 
				
			|||||||
            '-map 0:1',
 | 
					            '-map 0:1',
 | 
				
			||||||
            '-g 256',
 | 
					            '-g 256',
 | 
				
			||||||
            '-v verbose',
 | 
					            '-v verbose',
 | 
				
			||||||
 | 
					            '-vf scale=-2:720,format=yuv420p',
 | 
				
			||||||
            '-level 51',
 | 
					            '-level 51',
 | 
				
			||||||
            '-rc_mode 2',
 | 
					            '-rc_mode 2',
 | 
				
			||||||
            '-quality_min 51',
 | 
					            '-qp_init 30',
 | 
				
			||||||
            '-quality_max 51',
 | 
					 | 
				
			||||||
            '-width 1280',
 | 
					 | 
				
			||||||
            '-height 720',
 | 
					 | 
				
			||||||
          ],
 | 
					          ],
 | 
				
			||||||
          twoPass: false,
 | 
					          twoPass: false,
 | 
				
			||||||
          ffmpegPath: 'ffmpeg_mpp',
 | 
					 | 
				
			||||||
          ldLibraryPath: '/lib/aarch64-linux-gnu:/lib/ffmpeg-mpp',
 | 
					 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
				
			|||||||
@ -607,16 +607,6 @@ export class VAAPIConfig extends BaseHWConfig {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class RKMPPConfig extends BaseHWConfig {
 | 
					export class RKMPPConfig extends BaseHWConfig {
 | 
				
			||||||
  getOptions(target: TranscodeTarget, videoStream: VideoStreamInfo, audioStream?: AudioStreamInfo): TranscodeOptions {
 | 
					 | 
				
			||||||
    const options = super.getOptions(target, videoStream, audioStream);
 | 
					 | 
				
			||||||
    options.ffmpegPath = 'ffmpeg_mpp';
 | 
					 | 
				
			||||||
    options.ldLibraryPath = '/lib/aarch64-linux-gnu:/lib/ffmpeg-mpp';
 | 
					 | 
				
			||||||
    if ([TranscodeTarget.ALL, TranscodeTarget.VIDEO].includes(target)) {
 | 
					 | 
				
			||||||
      options.outputOptions.push(...this.getSizeOptions(videoStream));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return options;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  eligibleForTwoPass(): boolean {
 | 
					  eligibleForTwoPass(): boolean {
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -628,18 +618,6 @@ export class RKMPPConfig extends BaseHWConfig {
 | 
				
			|||||||
    return [];
 | 
					    return [];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getFilterOptions(videoStream: VideoStreamInfo) {
 | 
					 | 
				
			||||||
    return this.shouldToneMap(videoStream) ? this.getToneMapping() : [];
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  getSizeOptions(videoStream: VideoStreamInfo) {
 | 
					 | 
				
			||||||
    if (this.shouldScale(videoStream)) {
 | 
					 | 
				
			||||||
      const { width, height } = this.getSize(videoStream);
 | 
					 | 
				
			||||||
      return [`-width ${width}`, `-height ${height}`];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return [];
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  getPresetOptions() {
 | 
					  getPresetOptions() {
 | 
				
			||||||
    switch (this.config.targetVideoCodec) {
 | 
					    switch (this.config.targetVideoCodec) {
 | 
				
			||||||
      case VideoCodec.H264: {
 | 
					      case VideoCodec.H264: {
 | 
				
			||||||
@ -659,12 +637,11 @@ export class RKMPPConfig extends BaseHWConfig {
 | 
				
			|||||||
  getBitrateOptions() {
 | 
					  getBitrateOptions() {
 | 
				
			||||||
    const bitrate = this.getMaxBitrateValue();
 | 
					    const bitrate = this.getMaxBitrateValue();
 | 
				
			||||||
    if (bitrate > 0) {
 | 
					    if (bitrate > 0) {
 | 
				
			||||||
      return ['-rc_mode 3', '-quality_min 0', '-quality_max 100', `-b:v ${bitrate}${this.getBitrateUnit()}`];
 | 
					      // -b:v specifies max bitrate, average bitrate is derived automatically...
 | 
				
			||||||
    } else {
 | 
					      return ['-rc_mode 3', `-b:v ${bitrate}${this.getBitrateUnit()}`];
 | 
				
			||||||
      // convert CQP from 51-10 to 0-100, values below 10 are set to 10
 | 
					 | 
				
			||||||
      const quality = Math.floor(125 - Math.max(this.config.crf, 10) * (125 / 51));
 | 
					 | 
				
			||||||
      return ['-rc_mode 2', `-quality_min ${quality}`, `-quality_max ${quality}`];
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    // use CRF value as QP value
 | 
				
			||||||
 | 
					    return ['-rc_mode 2', `-qp_init ${this.config.crf}`];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getSupportedCodecs() {
 | 
					  getSupportedCodecs() {
 | 
				
			||||||
@ -672,6 +649,6 @@ export class RKMPPConfig extends BaseHWConfig {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getVideoCodec(): string {
 | 
					  getVideoCodec(): string {
 | 
				
			||||||
    return `${this.config.targetVideoCodec}_rkmpp_encoder`;
 | 
					    return `${this.config.targetVideoCodec}_rkmpp`;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -51,8 +51,6 @@ export interface TranscodeOptions {
 | 
				
			|||||||
  inputOptions: string[];
 | 
					  inputOptions: string[];
 | 
				
			||||||
  outputOptions: string[];
 | 
					  outputOptions: string[];
 | 
				
			||||||
  twoPass: boolean;
 | 
					  twoPass: boolean;
 | 
				
			||||||
  ffmpegPath?: string;
 | 
					 | 
				
			||||||
  ldLibraryPath?: string;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface BitrateDistribution {
 | 
					export interface BitrateDistribution {
 | 
				
			||||||
 | 
				
			|||||||
@ -76,18 +76,7 @@ export class MediaRepository implements IMediaRepository {
 | 
				
			|||||||
  transcode(input: string, output: string | Writable, options: TranscodeOptions): Promise<void> {
 | 
					  transcode(input: string, output: string | Writable, options: TranscodeOptions): Promise<void> {
 | 
				
			||||||
    if (!options.twoPass) {
 | 
					    if (!options.twoPass) {
 | 
				
			||||||
      return new Promise((resolve, reject) => {
 | 
					      return new Promise((resolve, reject) => {
 | 
				
			||||||
        const oldLdLibraryPath = process.env.LD_LIBRARY_PATH;
 | 
					 | 
				
			||||||
        if (options.ldLibraryPath) {
 | 
					 | 
				
			||||||
          // fluent ffmpeg does not allow to set environment variables, so we do it manually
 | 
					 | 
				
			||||||
          process.env.LD_LIBRARY_PATH = this.chainPath(oldLdLibraryPath || '', options.ldLibraryPath);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
        this.configureFfmpegCall(input, output, options).on('error', reject).on('end', resolve).run();
 | 
					        this.configureFfmpegCall(input, output, options).on('error', reject).on('end', resolve).run();
 | 
				
			||||||
        } finally {
 | 
					 | 
				
			||||||
          if (options.ldLibraryPath) {
 | 
					 | 
				
			||||||
            process.env.LD_LIBRARY_PATH = oldLdLibraryPath;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -121,7 +110,6 @@ export class MediaRepository implements IMediaRepository {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  configureFfmpegCall(input: string, output: string | Writable, options: TranscodeOptions) {
 | 
					  configureFfmpegCall(input: string, output: string | Writable, options: TranscodeOptions) {
 | 
				
			||||||
    return ffmpeg(input, { niceness: 10 })
 | 
					    return ffmpeg(input, { niceness: 10 })
 | 
				
			||||||
      .setFfmpegPath(options.ffmpegPath || 'ffmpeg')
 | 
					 | 
				
			||||||
      .inputOptions(options.inputOptions)
 | 
					      .inputOptions(options.inputOptions)
 | 
				
			||||||
      .outputOptions(options.outputOptions)
 | 
					      .outputOptions(options.outputOptions)
 | 
				
			||||||
      .output(output)
 | 
					      .output(output)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user