feat(server): easy RKMPP video encoding (#7460)

* feat(server): easy RKMPP video encoding

* make linter happy
This commit is contained in:
Fynn Petersen-Frey 2024-02-27 16:47:04 +01:00 committed by GitHub
parent cfb49c8be0
commit 5e485e35e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 11 additions and 63 deletions

View File

@ -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:

View File

@ -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',
}, },
); );
}); });

View File

@ -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`;
} }
} }

View File

@ -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 {

View File

@ -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; this.configureFfmpegCall(input, output, options).on('error', reject).on('end', resolve).run();
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();
} 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)