chore(server): separate ffmpeg arguments (#27937)

separate arguments
This commit is contained in:
Mert
2026-04-18 11:33:44 -04:00
committed by GitHub
parent be20cd2bf9
commit 0b1188e42e
2 changed files with 532 additions and 280 deletions
File diff suppressed because it is too large Load Diff
+120 -85
View File
@@ -91,14 +91,14 @@ export class BaseConfig implements VideoCodecSWConfig {
) { ) {
const options = { const options = {
inputOptions: this.getBaseInputOptions(videoStream, format), inputOptions: this.getBaseInputOptions(videoStream, format),
outputOptions: [...this.getBaseOutputOptions(target, videoStream, audioStream), '-v verbose'], outputOptions: [...this.getBaseOutputOptions(target, videoStream, audioStream), '-v', 'verbose'],
twoPass: this.eligibleForTwoPass(), twoPass: this.eligibleForTwoPass(),
progress: { frameCount: videoStream.frameCount, percentInterval: 5 }, progress: { frameCount: videoStream.frameCount, percentInterval: 5 },
} as TranscodeCommand; } as TranscodeCommand;
if ([TranscodeTarget.All, TranscodeTarget.Video].includes(target)) { if ([TranscodeTarget.All, TranscodeTarget.Video].includes(target)) {
const filters = this.getFilterOptions(videoStream); const filters = this.getFilterOptions(videoStream);
if (filters.length > 0) { if (filters.length > 0) {
options.outputOptions.push(`-vf ${filters.join(',')}`); options.outputOptions.push('-vf', filters.join(','));
} }
} }
@@ -121,36 +121,40 @@ export class BaseConfig implements VideoCodecSWConfig {
const audioCodec = [TranscodeTarget.All, TranscodeTarget.Audio].includes(target) ? this.getAudioEncoder() : 'copy'; const audioCodec = [TranscodeTarget.All, TranscodeTarget.Audio].includes(target) ? this.getAudioEncoder() : 'copy';
const options = [ const options = [
`-c:v ${videoCodec}`, '-c:v',
`-c:a ${audioCodec}`, videoCodec,
'-c:a',
audioCodec,
// Makes a second pass moving the moov atom to the // Makes a second pass moving the moov atom to the
// beginning of the file for improved playback speed. // beginning of the file for improved playback speed.
'-movflags faststart', '-movflags',
'-fps_mode passthrough', 'faststart',
// explicitly selects the video stream instead of leaving it up to FFmpeg '-fps_mode',
`-map 0:${videoStream.index}`, 'passthrough',
// Strip metadata like capture date, camera, and GPS '-map',
'-map_metadata -1', `0:${videoStream.index}`,
'-map_metadata',
'-1',
]; ];
if (audioStream) { if (audioStream) {
options.push(`-map 0:${audioStream.index}`); options.push('-map', `0:${audioStream.index}`);
} }
if (this.getBFrames() > -1) { if (this.getBFrames() > -1) {
options.push(`-bf ${this.getBFrames()}`); options.push('-bf', `${this.getBFrames()}`);
} }
if (this.getRefs() > 0) { if (this.getRefs() > 0) {
options.push(`-refs ${this.getRefs()}`); options.push('-refs', `${this.getRefs()}`);
} }
if (this.getGopSize() > 0) { if (this.getGopSize() > 0) {
options.push(`-g ${this.getGopSize()}`); options.push('-g', `${this.getGopSize()}`);
} }
if ( if (
this.config.targetVideoCodec === VideoCodec.Hevc && this.config.targetVideoCodec === VideoCodec.Hevc &&
(videoCodec !== 'copy' || videoStream.codecName === 'hevc') (videoCodec !== 'copy' || videoStream.codecName === 'hevc')
) { ) {
options.push('-tag:v hvc1'); options.push('-tag:v', 'hvc1');
} }
return options; return options;
@@ -173,26 +177,32 @@ export class BaseConfig implements VideoCodecSWConfig {
} }
getPresetOptions() { getPresetOptions() {
return [`-preset ${this.config.preset}`]; return ['-preset', this.config.preset];
} }
getBitrateOptions() { getBitrateOptions() {
const bitrates = this.getBitrateDistribution(); const bitrates = this.getBitrateDistribution();
if (this.eligibleForTwoPass()) { if (this.eligibleForTwoPass()) {
return [ return [
`-b:v ${bitrates.target}${bitrates.unit}`, '-b:v',
`-minrate ${bitrates.min}${bitrates.unit}`, `${bitrates.target}${bitrates.unit}`,
`-maxrate ${bitrates.max}${bitrates.unit}`, '-minrate',
`${bitrates.min}${bitrates.unit}`,
'-maxrate',
`${bitrates.max}${bitrates.unit}`,
]; ];
} else if (bitrates.max > 0) { } else if (bitrates.max > 0) {
// -bufsize is the peak possible bitrate at any moment, while -maxrate is the max rolling average bitrate // -bufsize is the peak possible bitrate at any moment, while -maxrate is the max rolling average bitrate
return [ return [
`-${this.useCQP() ? 'q:v' : 'crf'} ${this.config.crf}`, `-${this.useCQP() ? 'q:v' : 'crf'}`,
`-maxrate ${bitrates.max}${bitrates.unit}`, `${this.config.crf}`,
`-bufsize ${bitrates.max * 2}${bitrates.unit}`, '-maxrate',
`${bitrates.max}${bitrates.unit}`,
'-bufsize',
`${bitrates.max * 2}${bitrates.unit}`,
]; ];
} else { } else {
return [`-${this.useCQP() ? 'q:v' : 'crf'} ${this.config.crf}`]; return [`-${this.useCQP() ? 'q:v' : 'crf'}`, `${this.config.crf}`];
} }
} }
@@ -204,7 +214,7 @@ export class BaseConfig implements VideoCodecSWConfig {
if (this.config.threads <= 0) { if (this.config.threads <= 0) {
return []; return [];
} }
return [`-threads ${this.config.threads}`]; return ['-threads', `${this.config.threads}`];
} }
eligibleForTwoPass() { eligibleForTwoPass() {
@@ -395,8 +405,8 @@ export class ThumbnailConfig extends BaseConfig {
// skip_frame nointra skips all frames for some MPEG-TS files. Look at ffmpeg tickets 7950 and 7895 for more details. // skip_frame nointra skips all frames for some MPEG-TS files. Look at ffmpeg tickets 7950 and 7895 for more details.
const options = const options =
format?.formatName === 'mpegts' format?.formatName === 'mpegts'
? ['-sws_flags accurate_rnd+full_chroma_int'] ? ['-sws_flags', 'accurate_rnd+full_chroma_int']
: ['-skip_frame nointra', '-sws_flags accurate_rnd+full_chroma_int']; : ['-skip_frame', 'nointra', '-sws_flags', 'accurate_rnd+full_chroma_int'];
const metadataOverrides = []; const metadataOverrides = [];
if (videoStream.colorPrimaries === 'reserved') { if (videoStream.colorPrimaries === 'reserved') {
@@ -413,14 +423,14 @@ export class ThumbnailConfig extends BaseConfig {
if (metadataOverrides.length > 0) { if (metadataOverrides.length > 0) {
// workaround for https://fftrac-bg.ffmpeg.org/ticket/11020 // workaround for https://fftrac-bg.ffmpeg.org/ticket/11020
options.push(`-bsf:v ${videoStream.codecName}_metadata=${metadataOverrides.join(':')}`); options.push('-bsf:v', `${videoStream.codecName}_metadata=${metadataOverrides.join(':')}`);
} }
return options; return options;
} }
getBaseOutputOptions() { getBaseOutputOptions() {
return ['-fps_mode vfr', '-frames:v 1', '-update 1']; return ['-fps_mode', 'vfr', '-frames:v', '1', '-update', '1'];
} }
getFilterOptions(videoStream: VideoStreamInfo): string[] { getFilterOptions(videoStream: VideoStreamInfo): string[] {
@@ -455,7 +465,7 @@ export class H264Config extends BaseConfig {
getOutputThreadOptions() { getOutputThreadOptions() {
const options = super.getOutputThreadOptions(); const options = super.getOutputThreadOptions();
if (this.config.threads === 1) { if (this.config.threads === 1) {
options.push('-x264-params frame-threads=1:pools=none'); options.push('-x264-params', 'frame-threads=1:pools=none');
} }
return options; return options;
@@ -466,7 +476,7 @@ export class HEVCConfig extends BaseConfig {
getOutputThreadOptions() { getOutputThreadOptions() {
const options = super.getOutputThreadOptions(); const options = super.getOutputThreadOptions();
if (this.config.threads === 1) { if (this.config.threads === 1) {
options.push('-x265-params frame-threads=1:pools=none'); options.push('-x265-params', 'frame-threads=1:pools=none');
} }
return options; return options;
@@ -477,7 +487,7 @@ export class VP9Config extends BaseConfig {
getPresetOptions() { getPresetOptions() {
const speed = Math.min(this.getPresetIndex(), 5); // values over 5 require realtime mode, which is its own can of worms since it overrides -crf and -threads const speed = Math.min(this.getPresetIndex(), 5); // values over 5 require realtime mode, which is its own can of worms since it overrides -crf and -threads
if (speed >= 0) { if (speed >= 0) {
return [`-cpu-used ${speed}`]; return ['-cpu-used', `${speed}`];
} }
return []; return [];
} }
@@ -486,17 +496,20 @@ export class VP9Config extends BaseConfig {
const bitrates = this.getBitrateDistribution(); const bitrates = this.getBitrateDistribution();
if (bitrates.max > 0 && this.eligibleForTwoPass()) { if (bitrates.max > 0 && this.eligibleForTwoPass()) {
return [ return [
`-b:v ${bitrates.target}${bitrates.unit}`, '-b:v',
`-minrate ${bitrates.min}${bitrates.unit}`, `${bitrates.target}${bitrates.unit}`,
`-maxrate ${bitrates.max}${bitrates.unit}`, '-minrate',
`${bitrates.min}${bitrates.unit}`,
'-maxrate',
`${bitrates.max}${bitrates.unit}`,
]; ];
} }
return [`-${this.useCQP() ? 'q:v' : 'crf'} ${this.config.crf}`, `-b:v ${bitrates.max}${bitrates.unit}`]; return [`-${this.useCQP() ? 'q:v' : 'crf'}`, `${this.config.crf}`, '-b:v', `${bitrates.max}${bitrates.unit}`];
} }
getOutputThreadOptions() { getOutputThreadOptions() {
return ['-row-mt 1', ...super.getOutputThreadOptions()]; return ['-row-mt', '1', ...super.getOutputThreadOptions()];
} }
eligibleForTwoPass() { eligibleForTwoPass() {
@@ -512,13 +525,13 @@ export class AV1Config extends BaseConfig {
getPresetOptions() { getPresetOptions() {
const speed = this.getPresetIndex() + 4; // Use 4 as slowest, giving us an effective range of 4-12 which is far more useful than 0-8 const speed = this.getPresetIndex() + 4; // Use 4 as slowest, giving us an effective range of 4-12 which is far more useful than 0-8
if (speed >= 0) { if (speed >= 0) {
return [`-preset ${speed}`]; return ['-preset', `${speed}`];
} }
return []; return [];
} }
getBitrateOptions() { getBitrateOptions() {
const options = [`-crf ${this.config.crf}`]; const options = ['-crf', `${this.config.crf}`];
const bitrates = this.getBitrateDistribution(); const bitrates = this.getBitrateDistribution();
const svtparams = []; const svtparams = [];
if (this.config.threads > 0) { if (this.config.threads > 0) {
@@ -528,7 +541,7 @@ export class AV1Config extends BaseConfig {
svtparams.push(`mbr=${bitrates.max}${bitrates.unit}`); svtparams.push(`mbr=${bitrates.max}${bitrates.unit}`);
} }
if (svtparams.length > 0) { if (svtparams.length > 0) {
options.push(`-svtav1-params ${svtparams.join(':')}`); options.push('-svtav1-params', svtparams.join(':'));
} }
return options; return options;
} }
@@ -552,23 +565,27 @@ export class NvencSwDecodeConfig extends BaseHWConfig {
} }
getBaseInputOptions() { getBaseInputOptions() {
return [`-init_hw_device cuda=cuda:${this.device}`, '-filter_hw_device cuda']; return ['-init_hw_device', `cuda=cuda:${this.device}`, '-filter_hw_device', 'cuda'];
} }
getBaseOutputOptions(target: TranscodeTarget, videoStream: VideoStreamInfo, audioStream?: AudioStreamInfo) { getBaseOutputOptions(target: TranscodeTarget, videoStream: VideoStreamInfo, audioStream?: AudioStreamInfo) {
const options = [ const options = [
// below settings recommended from https://docs.nvidia.com/video-technologies/video-codec-sdk/12.0/ffmpeg-with-nvidia-gpu/index.html#command-line-for-latency-tolerant-high-quality-transcoding // below settings recommended from https://docs.nvidia.com/video-technologies/video-codec-sdk/12.0/ffmpeg-with-nvidia-gpu/index.html#command-line-for-latency-tolerant-high-quality-transcoding
'-tune hq', '-tune',
'-qmin 0', 'hq',
'-rc-lookahead 20', '-qmin',
'-i_qfactor 0.75', '0',
'-rc-lookahead',
'20',
'-i_qfactor',
'0.75',
...super.getBaseOutputOptions(target, videoStream, audioStream), ...super.getBaseOutputOptions(target, videoStream, audioStream),
]; ];
if (this.getBFrames() > 0) { if (this.getBFrames() > 0) {
options.push('-b_ref_mode middle', '-b_qfactor 1.1'); options.push('-b_ref_mode', 'middle', '-b_qfactor', '1.1');
} }
if (this.config.temporalAQ) { if (this.config.temporalAQ) {
options.push('-temporal-aq 1'); options.push('-temporal-aq', '1');
} }
return options; return options;
} }
@@ -589,26 +606,33 @@ export class NvencSwDecodeConfig extends BaseHWConfig {
return []; return [];
} }
presetIndex = 7 - Math.min(6, presetIndex); // map to p1-p7; p7 is the highest quality, so reverse index presetIndex = 7 - Math.min(6, presetIndex); // map to p1-p7; p7 is the highest quality, so reverse index
return [`-preset p${presetIndex}`]; return ['-preset', `p${presetIndex}`];
} }
getBitrateOptions() { getBitrateOptions() {
const bitrates = this.getBitrateDistribution(); const bitrates = this.getBitrateDistribution();
if (bitrates.max > 0 && this.config.twoPass) { if (bitrates.max > 0 && this.config.twoPass) {
return [ return [
`-b:v ${bitrates.target}${bitrates.unit}`, '-b:v',
`-maxrate ${bitrates.max}${bitrates.unit}`, `${bitrates.target}${bitrates.unit}`,
`-bufsize ${bitrates.target}${bitrates.unit}`, '-maxrate',
'-multipass 2', `${bitrates.max}${bitrates.unit}`,
'-bufsize',
`${bitrates.target}${bitrates.unit}`,
'-multipass',
'2',
]; ];
} else if (bitrates.max > 0) { } else if (bitrates.max > 0) {
return [ return [
`-cq:v ${this.config.crf}`, '-cq:v',
`-maxrate ${bitrates.max}${bitrates.unit}`, `${this.config.crf}`,
`-bufsize ${bitrates.target}${bitrates.unit}`, '-maxrate',
`${bitrates.max}${bitrates.unit}`,
'-bufsize',
`${bitrates.target}${bitrates.unit}`,
]; ];
} else { } else {
return [`-cq:v ${this.config.crf}`]; return ['-cq:v', `${this.config.crf}`];
} }
} }
@@ -627,7 +651,7 @@ export class NvencSwDecodeConfig extends BaseHWConfig {
export class NvencHwDecodeConfig extends NvencSwDecodeConfig { export class NvencHwDecodeConfig extends NvencSwDecodeConfig {
getBaseInputOptions() { getBaseInputOptions() {
return ['-hwaccel cuda', '-hwaccel_output_format cuda', '-noautorotate', ...this.getInputThreadOptions()]; return ['-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda', '-noautorotate', ...this.getInputThreadOptions()];
} }
getFilterOptions(videoStream: VideoStreamInfo) { getFilterOptions(videoStream: VideoStreamInfo) {
@@ -664,7 +688,7 @@ export class NvencHwDecodeConfig extends NvencSwDecodeConfig {
} }
getInputThreadOptions() { getInputThreadOptions() {
return [`-threads 1`]; return ['-threads', '1'];
} }
getOutputThreadOptions() { getOutputThreadOptions() {
@@ -674,14 +698,14 @@ export class NvencHwDecodeConfig extends NvencSwDecodeConfig {
export class QsvSwDecodeConfig extends BaseHWConfig { export class QsvSwDecodeConfig extends BaseHWConfig {
getBaseInputOptions() { getBaseInputOptions() {
return [`-init_hw_device qsv=hw,child_device=${this.device}`, '-filter_hw_device hw']; return ['-init_hw_device', `qsv=hw,child_device=${this.device}`, '-filter_hw_device', 'hw'];
} }
getBaseOutputOptions(target: TranscodeTarget, videoStream: VideoStreamInfo, audioStream?: AudioStreamInfo) { getBaseOutputOptions(target: TranscodeTarget, videoStream: VideoStreamInfo, audioStream?: AudioStreamInfo) {
const options = super.getBaseOutputOptions(target, videoStream, audioStream); const options = super.getBaseOutputOptions(target, videoStream, audioStream);
// VP9 requires enabling low power mode https://git.ffmpeg.org/gitweb/ffmpeg.git/commit/33583803e107b6d532def0f9d949364b01b6ad5a // VP9 requires enabling low power mode https://git.ffmpeg.org/gitweb/ffmpeg.git/commit/33583803e107b6d532def0f9d949364b01b6ad5a
if (this.config.targetVideoCodec === VideoCodec.Vp9) { if (this.config.targetVideoCodec === VideoCodec.Vp9) {
options.push('-low_power 1'); options.push('-low_power', '1');
} }
return options; return options;
} }
@@ -701,14 +725,14 @@ export class QsvSwDecodeConfig extends BaseHWConfig {
return []; return [];
} }
presetIndex = Math.min(6, presetIndex) + 1; // 1 to 7 presetIndex = Math.min(6, presetIndex) + 1; // 1 to 7
return [`-preset ${presetIndex}`]; return ['-preset', `${presetIndex}`];
} }
getBitrateOptions() { getBitrateOptions() {
const options = [`-${this.useCQP() ? 'q:v' : 'global_quality:v'} ${this.config.crf}`]; const options = [`-${this.useCQP() ? 'q:v' : 'global_quality:v'}`, `${this.config.crf}`];
const bitrates = this.getBitrateDistribution(); const bitrates = this.getBitrateDistribution();
if (bitrates.max > 0) { if (bitrates.max > 0) {
options.push(`-maxrate ${bitrates.max}${bitrates.unit}`, `-bufsize ${bitrates.max * 2}${bitrates.unit}`); options.push('-maxrate', `${bitrates.max}${bitrates.unit}`, '-bufsize', `${bitrates.max * 2}${bitrates.unit}`);
} }
return options; return options;
} }
@@ -744,11 +768,15 @@ export class QsvSwDecodeConfig extends BaseHWConfig {
export class QsvHwDecodeConfig extends QsvSwDecodeConfig { export class QsvHwDecodeConfig extends QsvSwDecodeConfig {
getBaseInputOptions() { getBaseInputOptions() {
return [ return [
'-hwaccel qsv', '-hwaccel',
'-hwaccel_output_format qsv', 'qsv',
'-async_depth 4', '-hwaccel_output_format',
'qsv',
'-async_depth',
'4',
'-noautorotate', '-noautorotate',
`-qsv_device ${this.device}`, '-qsv_device',
this.device,
...this.getInputThreadOptions(), ...this.getInputThreadOptions(),
]; ];
} }
@@ -791,13 +819,13 @@ export class QsvHwDecodeConfig extends QsvSwDecodeConfig {
} }
getInputThreadOptions() { getInputThreadOptions() {
return [`-threads 1`]; return ['-threads', '1'];
} }
} }
export class VaapiSwDecodeConfig extends BaseHWConfig { export class VaapiSwDecodeConfig extends BaseHWConfig {
getBaseInputOptions() { getBaseInputOptions() {
return [`-init_hw_device vaapi=accel:${this.device}`, '-filter_hw_device accel']; return ['-init_hw_device', `vaapi=accel:${this.device}`, '-filter_hw_device', 'accel'];
} }
getFilterOptions(videoStream: VideoStreamInfo) { getFilterOptions(videoStream: VideoStreamInfo) {
@@ -816,7 +844,7 @@ export class VaapiSwDecodeConfig extends BaseHWConfig {
return []; return [];
} }
presetIndex = Math.min(6, presetIndex) + 1; // 1 to 7 presetIndex = Math.min(6, presetIndex) + 1; // 1 to 7
return [`-compression_level ${presetIndex}`]; return ['-compression_level', `${presetIndex}`];
} }
getBitrateOptions() { getBitrateOptions() {
@@ -824,21 +852,25 @@ export class VaapiSwDecodeConfig extends BaseHWConfig {
const options = []; const options = [];
if (this.config.targetVideoCodec === VideoCodec.Vp9) { if (this.config.targetVideoCodec === VideoCodec.Vp9) {
options.push('-bsf:v vp9_raw_reorder,vp9_superframe'); options.push('-bsf:v', 'vp9_raw_reorder,vp9_superframe');
} }
// VAAPI doesn't allow setting both quality and max bitrate // VAAPI doesn't allow setting both quality and max bitrate
if (bitrates.max > 0) { if (bitrates.max > 0) {
options.push( options.push(
`-b:v ${bitrates.target}${bitrates.unit}`, '-b:v',
`-maxrate ${bitrates.max}${bitrates.unit}`, `${bitrates.target}${bitrates.unit}`,
`-minrate ${bitrates.min}${bitrates.unit}`, '-maxrate',
'-rc_mode 3', `${bitrates.max}${bitrates.unit}`,
'-minrate',
`${bitrates.min}${bitrates.unit}`,
'-rc_mode',
'3',
); // variable bitrate ); // variable bitrate
} else if (this.useCQP()) { } else if (this.useCQP()) {
options.push(`-qp:v ${this.config.crf}`, `-global_quality:v ${this.config.crf}`, '-rc_mode 1'); options.push('-qp:v', `${this.config.crf}`, '-global_quality:v', `${this.config.crf}`, '-rc_mode', '1');
} else { } else {
options.push(`-global_quality:v ${this.config.crf}`, '-rc_mode 4'); options.push('-global_quality:v', `${this.config.crf}`, '-rc_mode', '4');
} }
return options; return options;
@@ -856,10 +888,13 @@ export class VaapiSwDecodeConfig extends BaseHWConfig {
export class VaapiHwDecodeConfig extends VaapiSwDecodeConfig { export class VaapiHwDecodeConfig extends VaapiSwDecodeConfig {
getBaseInputOptions() { getBaseInputOptions() {
return [ return [
'-hwaccel vaapi', '-hwaccel',
'-hwaccel_output_format vaapi', 'vaapi',
'-hwaccel_output_format',
'vaapi',
'-noautorotate', '-noautorotate',
`-hwaccel_device ${this.device}`, '-hwaccel_device',
this.device,
...this.getInputThreadOptions(), ...this.getInputThreadOptions(),
]; ];
} }
@@ -902,7 +937,7 @@ export class VaapiHwDecodeConfig extends VaapiSwDecodeConfig {
} }
getInputThreadOptions() { getInputThreadOptions() {
return [`-threads 1`]; return ['-threads', '1'];
} }
} }
@@ -919,11 +954,11 @@ export class RkmppSwDecodeConfig extends BaseHWConfig {
switch (this.config.targetVideoCodec) { switch (this.config.targetVideoCodec) {
case VideoCodec.H264: { case VideoCodec.H264: {
// from ffmpeg_mpp help, commonly referred to as H264 level 5.1 // from ffmpeg_mpp help, commonly referred to as H264 level 5.1
return ['-level 51']; return ['-level', '51'];
} }
case VideoCodec.Hevc: { case VideoCodec.Hevc: {
// from ffmpeg_mpp help, commonly referred to as HEVC level 5.1 // from ffmpeg_mpp help, commonly referred to as HEVC level 5.1
return ['-level 153']; return ['-level', '153'];
} }
default: { default: {
throw new Error(`Incompatible video codec for RKMPP: ${this.config.targetVideoCodec}`); throw new Error(`Incompatible video codec for RKMPP: ${this.config.targetVideoCodec}`);
@@ -935,10 +970,10 @@ export class RkmppSwDecodeConfig extends BaseHWConfig {
const bitrate = this.getMaxBitrateValue(); const bitrate = this.getMaxBitrateValue();
if (bitrate > 0) { if (bitrate > 0) {
// -b:v specifies max bitrate, average bitrate is derived automatically... // -b:v specifies max bitrate, average bitrate is derived automatically...
return ['-rc_mode AVBR', `-b:v ${bitrate}${this.getBitrateUnit()}`]; return ['-rc_mode', 'AVBR', '-b:v', `${bitrate}${this.getBitrateUnit()}`];
} }
// use CRF value as QP value // use CRF value as QP value
return ['-rc_mode CQP', `-qp_init ${this.config.crf}`]; return ['-rc_mode', 'CQP', '-qp_init', `${this.config.crf}`];
} }
getSupportedCodecs() { getSupportedCodecs() {
@@ -952,7 +987,7 @@ export class RkmppSwDecodeConfig extends BaseHWConfig {
export class RkmppHwDecodeConfig extends RkmppSwDecodeConfig { export class RkmppHwDecodeConfig extends RkmppSwDecodeConfig {
getBaseInputOptions() { getBaseInputOptions() {
return ['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga', '-noautorotate']; return ['-hwaccel', 'rkmpp', '-hwaccel_output_format', 'drm_prime', '-afbc', 'rga', '-noautorotate'];
} }
getFilterOptions(videoStream: VideoStreamInfo) { getFilterOptions(videoStream: VideoStreamInfo) {