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

使用SharpAVI为图像序列生成的视频添加音频时仅开头有声音

问题:SharpAVI生成视频仅开头有少量声音,后续无音频

问题场景

使用SharpAVI库将图像序列生成视频并添加音频,配置和写入代码如下:

初始化配置代码

var audioFileName = Path.Combine(m_rootDir, "audio", "v1.wav");
m_videoFileWritter=new AviWriter(m_videoFileName);
m_videoFileWritter.FramesPerSecond  = m_frameRate;
m_videoFileWritter.EmitIndex1 = true;
m_videoStream = m_videoFileWritter.AddMJpegWpfVideoStream(data.width, data.height, 70);
m_audioStream = m_videoFileWritter.AddAudioStream(channelCount: 2, samplesPerSecond: 44100, bitsPerSample: 16);
m_audioData = File.ReadAllBytes(audioFileName);
m_audioByteRate = (int)Math.Ceiling(m_audioStream.BitsPerSample / 8.0 * m_audioStream.ChannelCount * m_audioStream.SamplesPerSecond);
m_audioBlockSize = (int)Math.Ceiling(m_audioByteRate / m_videoFileWritter.FramesPerSecond);
m_audioBuffer = new byte[m_audioBlockSize];

帧写入代码

bool AddFrameToStream(Bitmap image)
{
    var buffer = new byte[m_data.width * m_data.height * 4];
    var bits = image.LockBits(new Rectangle(0, 0, m_data.width, m_data.height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
    Marshal.Copy(bits.Scan0, buffer, 0, buffer.Length);
    m_videoStream.WriteFrame(true, buffer, 0, buffer.Length);
    image.UnlockBits(bits);

    if(m_audioDataPoiner + m_audioBlockSize < m_audioData.Length)
    {
        Buffer.BlockCopy(m_audioData, m_audioDataPoiner, m_audioBuffer, 0, m_audioBlockSize);
        m_audioDataPoiner += m_audioBlockSize;
        
    }
    else
    {
          Console.WriteLine("error");
    }
    m_audioStream.WriteBlock(m_audioBuffer, 0, m_audioBuffer.Length);
    return true;
}

运行后视频显示正常,但仅开头有少量声音,后续无音频。已确认音频文件时长足够覆盖视频,且未触发错误分支。


问题根源及解决方案

1. 核心问题:未剥离WAV文件头

SharpAVI的音频流要求写入原始PCM采样数据,但File.ReadAllBytes读取的是完整WAV文件,包含前44字节的文件头(描述音频格式的元数据)。这些头数据并非有效音频采样,被写入后会导致播放器解析异常,后续实际音频数据位置偏移,最终表现为后续无声音。

修正方法:解析WAV文件,剥离头数据

// 替换原m_audioData = File.ReadAllBytes(audioFileName);
using (var fs = new FileStream(audioFileName, FileMode.Open, FileAccess.Read))
using (var reader = new BinaryReader(fs))
{
    // 跳过标准PCM WAV的44字节文件头
    fs.Seek(44, SeekOrigin.Begin);
    m_audioData = reader.ReadBytes((int)(fs.Length - 44));
}

2. 音频块计算与边界处理错误

  • 原代码用Math.Ceiling计算字节率和块大小,实际上参数均为整数,结果必然是整数,无需Ceiling,冗余计算可能导致块大小偏大,累积后提前耗尽音频数据。
  • 边界判断条件m_audioDataPoiner + m_audioBlockSize < m_audioData.Length会跳过最后一段刚好等于块大小的音频,且未处理剩余不足一个块的情况,导致无效数据写入。

修正后的计算逻辑

// 简化字节率计算(无需求整)
m_audioByteRate = m_audioStream.BitsPerSample / 8 * m_audioStream.ChannelCount * m_audioStream.SamplesPerSecond;
// 每帧对应的音频块大小,直接整数除法
m_audioBlockSize = m_audioByteRate / m_videoFileWritter.FramesPerSecond;

修正后的帧写入方法

bool AddFrameToStream(Bitmap image)
{
    var buffer = new byte[m_data.width * m_data.height * 4];
    var bits = image.LockBits(new Rectangle(0, 0, m_data.width, m_data.height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
    Marshal.Copy(bits.Scan0, buffer, 0, buffer.Length);
    m_videoStream.WriteFrame(true, buffer, 0, buffer.Length);
    image.UnlockBits(bits);

    int bytesToWrite = m_audioBlockSize;
    // 检查剩余音频是否足够一个块
    if (m_audioDataPoiner + bytesToWrite > m_audioData.Length)
    {
        bytesToWrite = m_audioData.Length - m_audioDataPoiner;
        // 剩余数据为0时填充静音
        if (bytesToWrite <= 0)
        {
            Array.Clear(m_audioBuffer, 0, m_audioBlockSize);
            m_audioStream.WriteBlock(m_audioBuffer, 0, m_audioBlockSize);
            return true;
        }
    }

    // 复制有效音频数据
    Buffer.BlockCopy(m_audioData, m_audioDataPoiner, m_audioBuffer, 0, bytesToWrite);
    // 不足一个块的部分填充静音
    if (bytesToWrite < m_audioBlockSize)
    {
        Array.Clear(m_audioBuffer, bytesToWrite, m_audioBlockSize - bytesToWrite);
    }

    m_audioDataPoiner += bytesToWrite;
    m_audioStream.WriteBlock(m_audioBuffer, 0, m_audioBlockSize);
    
    return true;
}

3. 额外注意事项

  • 确保WAV文件的格式参数(声道数、采样率、位深)与AddAudioStream的配置完全一致,否则音频会播放异常。
  • 初始化时需将m_audioDataPoiner设为0,避免未初始化导致的索引错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 09:25:05