You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenSMILE因音频段过短返回NaN的问题求解

解决OpenSMILE处理超短音频段返回NaN的问题

核心原因

1/30秒(约33毫秒)的音频段长度远小于OpenSMILE默认的特征提取窗口(通常帧长20-50ms、移窗10ms),无法完成有效特征计算,因此返回全NaN数组。

可行解决方案

1. 调整音频段长度,匹配OpenSMILE最小输入要求

OpenSMILE提取LLD特征至少需要一帧以上的音频数据,建议保留视频30fps采样节奏的同时,扩展音频提取窗口:

  • 视频仍每1/30秒取一帧
  • 音频以当前视频帧时间戳为中心,扩展到至少50ms的时长
  • 或合并相邻33ms音频段提取特征,再通过均值/插值映射到对应视频帧

示例代码调整(基于PyAV):

import av
import opensmile
import numpy as np

smile = opensmile.Smile(
    feature_set=opensmile.FeatureSet.ComParE_2016,
    feature_level=opensmile.FeatureLevel.LowLevelDescriptors,
)

container = av.open("input_video.mp4")
video_stream = container.streams.video[0]
audio_stream = container.streams.audio[0]

target_frame_interval = 1/30  # 视频30fps间隔
audio_window_duration = 0.05  # 调整为50ms音频窗口

for video_frame in container.decode(video_stream):
    frame_ts = video_frame.time
    # 计算音频窗口的起止时间(以视频帧时间为中心)
    audio_start_ts = max(0, frame_ts - audio_window_duration/2)
    audio_end_ts = frame_ts + audio_window_duration/2
    
    # 定位音频流并累积对应片段
    container.seek(int(audio_start_ts * av.time_base), stream=audio_stream)
    audio_frames = []
    for audio_frame in container.decode(audio_stream):
        if audio_frame.time > audio_end_ts:
            break
        audio_frames.append(audio_frame)
    
    if audio_frames:
        # 合并音频帧为numpy数组
        audio_np = np.concatenate([f.to_ndarray() for f in audio_frames], axis=0)
        # 提取特征
        features = smile.process_signal(audio_np, sample_rate=audio_stream.sample_rate)
        # 后续与视频MediaPipe特征拼接...
    else:
        # 处理视频开头/结尾的音频边界情况
        pass

2. 修改OpenSMILE配置文件,降低最小窗口要求

若必须严格使用1/30秒音频段,可自定义配置缩小帧长和移窗:

  • 复制OpenSMILE默认LLD配置文件(如config/ComParE_2016.conf)
  • 修改cFramer组件的frameSize和frameStep为对应33ms的样本数(如16000采样率下,33ms对应528样本)
  • 注意:过小窗口会降低特征鲁棒性,部分频域特征可能仍无法计算,需测试调整

示例配置片段修改:

[framer:cFramer]
reader.dmLevel=wave
writer.dmLevel=frame
frameSize=528  # 33ms @ 16000Hz
frameStep=528
frameCenterSpecial=left

3. 预提取全音频特征,插值映射到视频帧时间点

  • 先提取整个音频流的LLD特征(用OpenSMILE默认窗口),得到带时间戳的特征序列
  • 对每个30fps视频帧的时间点,用线性插值或最近邻匹配获取对应音频特征
  • 这种方法既保证音频特征有效性,又能严格对齐视频采样节奏

示例代码思路:

# 先提取全音频的LLD特征
full_audio_np = []
for audio_frame in container.decode(audio_stream):
    full_audio_np.append(audio_frame.to_ndarray())
full_audio_np = np.concatenate(full_audio_np, axis=0)
full_features = smile.process_signal(full_audio_np, sample_rate=audio_stream.sample_rate)

# 遍历视频帧,插值匹配音频特征
for video_frame in container.decode(video_stream):
    frame_ts = video_frame.time
    # 找到相邻的音频特征时间点
    prev_row = full_features[full_features['start'] <= frame_ts].iloc[-1]
    next_row = full_features[full_features['end'] >= frame_ts].iloc[0]
    # 线性插值得到当前帧对应的音频特征
    interpolated_feature = np.interp(
        frame_ts,
        [prev_row['start'], next_row['end']],
        [prev_row.values[2:], next_row.values[2:]]  # 跳过时间戳列
    )
    # 拼接视频MediaPipe特征...

验证建议

添加日志输出音频段的实际时长和样本数,确认满足OpenSMILE要求:

audio_duration = audio_end_ts - audio_start_ts
sample_count = len(audio_np)
print(f"Audio segment: {audio_duration:.3f}s, {sample_count} samples")

内容的提问来源于stack exchange,提问作者rashad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 00:05:05