Golang中如何切割音频文件

Golang中如何切割音频文件 是否有方法在Go中按时间戳截取音频文件?

3 回复

从零开始实现相当繁琐且困难(例如分析音频文件头、解析等)。你总是可以借助绑定库。很久以前我确实直接使用 soxffmpeg 命令来处理音频,并且我很确定 Go 语言中有相关的绑定库,但对于这类任务,你总可以借助一个简单的 bash 脚本。是否有任何编程实现的需求?这个链接可能会有所帮助:https://github.com/avelino/awesome-go#audio-and-music。

更多关于Golang中如何切割音频文件的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


音频是如何存储的?这里的时间戳是什么意思?

如果你知道未压缩音频的帧位置,那么这基本上就是复制数组或将其写入文件。如果是压缩音频,你需要注意这可能还涉及音频块/数据块,处理起来并不那么简单。如果时间戳意味着你已将元数据(如循环点)放入WAV文件中,那么这又需要不同的代码。

也许描述一下你项目的目标是个好主意,或者在询问事物如何运作时尽量具体。此外,如果你深入研究音频,可以尝试在KVR的DSP论坛上以C/C++语言提问。https://www.kvraudio.com/forum/viewforum.php?f=33

对于音频相关的内容,Go语言本身并没有提供大量内置库,所以最好的方式——我认为——是先在C/C++中获取音频知识,然后再将其转换为Go。主要区别在于语言本身,并且你最终可能会使用syscall来动态链接到某些库。

在Go中可以通过解码音频文件后按时间戳截取音频数据。以下是使用go-audiogoav库的示例:

package main

import (
    "fmt"
    "os"
    "time"
    
    "github.com/go-audio/audio"
    "github.com/go-audio/wav"
    "github.com/giorgisio/goav/avcodec"
    "github.com/giorgisio/goav/avformat"
    "github.com/giorgisio/goav/avutil"
)

// WAV文件截取示例
func trimWavFile(inputPath, outputPath string, start, duration time.Duration) error {
    // 打开输入文件
    inFile, err := os.Open(inputPath)
    if err != nil {
        return err
    }
    defer inFile.Close()
    
    // 解码WAV文件
    decoder := wav.NewDecoder(inFile)
    buf, err := decoder.FullPCMBuffer()
    if err != nil {
        return err
    }
    
    // 计算采样位置
    sampleRate := decoder.SampleRate
    startSample := int(float64(start.Seconds()) * float64(sampleRate))
    endSample := int(float64((start + duration).Seconds()) * float64(sampleRate))
    
    // 确保不超出范围
    if startSample < 0 {
        startSample = 0
    }
    if endSample > buf.NumFrames() {
        endSample = buf.NumFrames()
    }
    
    // 创建输出缓冲区
    outBuf := &audio.IntBuffer{
        Format: &audio.Format{
            NumChannels: decoder.Format().NumChannels,
            SampleRate:  sampleRate,
        },
        Data: make([]int, (endSample-startSample)*decoder.Format().NumChannels),
    }
    
    // 复制数据
    copy(outBuf.Data, buf.Data[startSample*decoder.Format().NumChannels:endSample*decoder.Format().NumChannels])
    
    // 创建输出文件
    outFile, err := os.Create(outputPath)
    if err != nil {
        return err
    }
    defer outFile.Close()
    
    // 编码为WAV
    encoder := wav.NewEncoder(outFile, sampleRate, 16, decoder.Format().NumChannels, 1)
    if err := encoder.Write(outBuf); err != nil {
        return err
    }
    
    return encoder.Close()
}

// FFmpeg封装示例(需要系统安装FFmpeg)
func trimAudioFFmpeg(inputPath, outputPath string, start, duration time.Duration) error {
    ctx := avformat.AvformatAllocContext()
    if avformat.AvformatOpenInput(&ctx, inputPath, nil, nil) < 0 {
        return fmt.Errorf("无法打开输入文件")
    }
    defer ctx.AvformatCloseInput()
    
    if ctx.AvformatFindStreamInfo(nil) < 0 {
        return fmt.Errorf("无法获取流信息")
    }
    
    // 这里需要实现完整的FFmpeg解码、截取和编码逻辑
    // 实际实现会更复杂,涉及数据包处理和时间戳转换
    
    return nil
}

func main() {
    // 示例:截取WAV文件的前10秒
    err := trimWavFile("input.wav", "output.wav", 0, 10*time.Second)
    if err != nil {
        fmt.Printf("错误: %v\n", err)
    }
}

对于MP3等压缩格式,推荐使用goav(FFmpeg绑定)或调用外部FFmpeg:

// 使用exec调用FFmpeg
func trimWithFFmpeg(input, output string, start, end time.Duration) error {
    cmd := exec.Command("ffmpeg",
        "-i", input,
        "-ss", fmt.Sprintf("%.2f", start.Seconds()),
        "-t", fmt.Sprintf("%.2f", (end-start).Seconds()),
        "-acodec", "copy",
        output)
    
    return cmd.Run()
}

注意:处理压缩音频需要完整的解码/编码流程,goav的实现较为复杂。实际项目中建议根据具体音频格式选择合适的库。

回到顶部