You've already forked FrameTour-RenderWorker
feat(audio): 添加全局音频淡入淡出功能
- 在 Task 类中新增 get_global_audio_fade_in_ms 和 get_global_audio_fade_out_ms 方法 - 修改 prepare_audio.py 中的音频混音逻辑,支持全局淡入淡出参数 - 新增 _build_global_fade_filters 静态方法构建全局淡入淡出滤镜 - 更新音频混音命令构建逻辑,支持在混音后应用全局淡入淡出效果 - 为无BGM和仅BGM的情况添加全局淡入淡出滤镜支持 - 在amix混音后追加全局淡入淡出滤镜,与片段级音频效果独立处理
This commit is contained in:
@@ -110,12 +110,16 @@ class PrepareJobAudioHandler(BaseHandler):
|
||||
|
||||
# 2. 构建音频混音命令
|
||||
output_file = os.path.join(work_dir, 'audio_full.aac')
|
||||
global_fade_in_ms = task.get_global_audio_fade_in_ms()
|
||||
global_fade_out_ms = task.get_global_audio_fade_out_ms()
|
||||
cmd = self._build_audio_command(
|
||||
bgm_file=bgm_file,
|
||||
sfx_files=sfx_files,
|
||||
output_file=output_file,
|
||||
total_duration_sec=total_duration_sec,
|
||||
audio_profile=audio_profile
|
||||
audio_profile=audio_profile,
|
||||
global_fade_in_ms=global_fade_in_ms,
|
||||
global_fade_out_ms=global_fade_out_ms
|
||||
)
|
||||
|
||||
# 3. 执行 FFmpeg
|
||||
@@ -157,7 +161,9 @@ class PrepareJobAudioHandler(BaseHandler):
|
||||
sfx_files: List[Dict],
|
||||
output_file: str,
|
||||
total_duration_sec: float,
|
||||
audio_profile: AudioProfile
|
||||
audio_profile: AudioProfile,
|
||||
global_fade_in_ms: int = 0,
|
||||
global_fade_out_ms: int = 0
|
||||
) -> List[str]:
|
||||
"""
|
||||
构建音频混音命令
|
||||
@@ -168,6 +174,8 @@ class PrepareJobAudioHandler(BaseHandler):
|
||||
output_file: 输出文件路径
|
||||
total_duration_sec: 总时长(秒)
|
||||
audio_profile: 音频配置
|
||||
global_fade_in_ms: 全局音频淡入时长(毫秒),0 不应用
|
||||
global_fade_out_ms: 全局音频淡出时长(毫秒),0 不应用
|
||||
|
||||
Returns:
|
||||
FFmpeg 命令参数列表
|
||||
@@ -175,8 +183,23 @@ class PrepareJobAudioHandler(BaseHandler):
|
||||
sample_rate = audio_profile.sample_rate
|
||||
channels = audio_profile.channels
|
||||
|
||||
# 构建全局 afade 滤镜(作用于最终混合音频,在 amix 之后)
|
||||
global_fade_filters = self._build_global_fade_filters(
|
||||
total_duration_sec, global_fade_in_ms, global_fade_out_ms
|
||||
)
|
||||
|
||||
# 情况1:无 BGM 也无叠加音效 -> 生成静音
|
||||
if not bgm_file and not sfx_files:
|
||||
if global_fade_filters:
|
||||
return [
|
||||
'ffmpeg', '-y', '-hide_banner',
|
||||
'-f', 'lavfi',
|
||||
'-i', f'anullsrc=r={sample_rate}:cl=stereo',
|
||||
'-t', str(total_duration_sec),
|
||||
'-af', ','.join(global_fade_filters),
|
||||
'-c:a', 'aac', '-b:a', '128k',
|
||||
output_file
|
||||
]
|
||||
return [
|
||||
'ffmpeg', '-y', '-hide_banner',
|
||||
'-f', 'lavfi',
|
||||
@@ -188,10 +211,14 @@ class PrepareJobAudioHandler(BaseHandler):
|
||||
|
||||
# 情况2:仅 BGM,无叠加音效
|
||||
if not sfx_files:
|
||||
af_arg = []
|
||||
if global_fade_filters:
|
||||
af_arg = ['-af', ','.join(global_fade_filters)]
|
||||
return [
|
||||
'ffmpeg', '-y', '-hide_banner',
|
||||
'-i', bgm_file,
|
||||
'-t', str(total_duration_sec),
|
||||
*af_arg,
|
||||
'-c:a', 'aac', '-b:a', '128k',
|
||||
'-ar', str(sample_rate), '-ac', str(channels),
|
||||
output_file
|
||||
@@ -261,10 +288,21 @@ class PrepareJobAudioHandler(BaseHandler):
|
||||
# dropout_transition=0 表示输入结束时不做渐变
|
||||
mix_inputs = "[bgm]" + "".join(sfx_labels)
|
||||
num_inputs = 1 + len(sfx_files)
|
||||
filter_parts.append(
|
||||
f"{mix_inputs}amix=inputs={num_inputs}:duration=first:"
|
||||
f"dropout_transition=0:normalize=0[out]"
|
||||
)
|
||||
|
||||
# 如果有全局 fade,amix 输出到中间标签后再追加 afade;否则直接输出到 [out]
|
||||
if global_fade_filters:
|
||||
filter_parts.append(
|
||||
f"{mix_inputs}amix=inputs={num_inputs}:duration=first:"
|
||||
f"dropout_transition=0:normalize=0[mixed]"
|
||||
)
|
||||
filter_parts.append(
|
||||
f"[mixed]{','.join(global_fade_filters)}[out]"
|
||||
)
|
||||
else:
|
||||
filter_parts.append(
|
||||
f"{mix_inputs}amix=inputs={num_inputs}:duration=first:"
|
||||
f"dropout_transition=0:normalize=0[out]"
|
||||
)
|
||||
|
||||
filter_complex = ';'.join(filter_parts)
|
||||
|
||||
@@ -277,3 +315,33 @@ class PrepareJobAudioHandler(BaseHandler):
|
||||
]
|
||||
|
||||
return cmd
|
||||
|
||||
@staticmethod
|
||||
def _build_global_fade_filters(
|
||||
total_duration_sec: float,
|
||||
global_fade_in_ms: int,
|
||||
global_fade_out_ms: int
|
||||
) -> List[str]:
|
||||
"""
|
||||
构建全局音频淡入/淡出滤镜列表
|
||||
|
||||
在 amix 混音输出之后追加,作用于最终混合音频。
|
||||
与片段级 audioSpecJson 中的 fadeInMs/fadeOutMs(仅作用于单个叠加音效)独立。
|
||||
|
||||
Args:
|
||||
total_duration_sec: 总时长(秒)
|
||||
global_fade_in_ms: 全局淡入时长(毫秒),0 不应用
|
||||
global_fade_out_ms: 全局淡出时长(毫秒),0 不应用
|
||||
|
||||
Returns:
|
||||
afade 滤镜字符串列表,可能为空
|
||||
"""
|
||||
filters = []
|
||||
if global_fade_in_ms > 0:
|
||||
fade_in_sec = global_fade_in_ms / 1000.0
|
||||
filters.append(f"afade=t=in:st=0:d={fade_in_sec}")
|
||||
if global_fade_out_ms > 0:
|
||||
fade_out_sec = global_fade_out_ms / 1000.0
|
||||
fade_out_start = total_duration_sec - fade_out_sec
|
||||
filters.append(f"afade=t=out:st={fade_out_start}:d={fade_out_sec}")
|
||||
return filters
|
||||
|
||||
Reference in New Issue
Block a user