golang轻量级MP3解码器插件库minimp3的使用
Golang轻量级MP3解码器插件库minimp3的使用
minimp3是一个基于C语言minimp3库的Go语言封装,用于解码MP3音频文件。它是一个轻量级的解决方案,适合在Go项目中处理MP3音频。
安装
- 首先需要安装Go(要求Go 1.15+版本),然后使用以下命令安装minimp3:
$ go get -u github.com/tosone/minimp3
- 在代码中导入:
import "github.com/tosone/minimp3"
使用示例
示例1:解码整个MP3文件并播放
package main
import (
"io/ioutil"
"log"
"time"
"github.com/hajimehoshi/oto"
"github.com/tosone/minimp3"
)
func main() {
var err error
var file []byte
if file, err = ioutil.ReadFile("test.mp3"); err != nil {
log.Fatal(err)
}
var dec *minimp3.Decoder
var data []byte
if dec, data, err = minimp3.DecodeFull(file); err != nil {
log.Fatal(err)
}
var context *oto.Context
if context, err = oto.NewContext(dec.SampleRate, dec.Channels, 2, 1024); err != nil {
log.Fatal(err)
}
var player = context.NewPlayer()
player.Write(data)
<-time.After(time.Second)
dec.Close()
if err = player.Close(); err != nil {
log.Fatal(err)
}
}
示例2:流式解码并播放
package main
import (
"io"
"log"
"os"
"sync"
"time"
"github.com/hajimehoshi/oto"
"github.com/tosone/minimp3"
)
func main() {
var err error
var file *os.File
if file, err = os.Open("../test.mp3"); err != nil {
log.Fatal(err)
}
var dec *minimp3.Decoder
if dec, err = minimp3.NewDecoder(file); err != nil {
log.Fatal(err)
}
started := dec.Started()
<-started
log.Printf("Convert audio sample rate: %d, channels: %d\n", dec.SampleRate, dec.Channels)
var context *oto.Context
if context, err = oto.NewContext(dec.SampleRate, dec.Channels, 2, 1024); err != nil {
log.Fatal(err)
}
var waitForPlayOver = new(sync.WaitGroup)
waitForPlayOver.Add(1)
var player = context.NewPlayer()
go func() {
for {
var data = make([]byte, 1024)
_, err := dec.Read(data)
if err == io.EOF {
break
}
if err != nil {
break
}
player.Write(data)
}
log.Println("over play.")
waitForPlayOver.Done()
}()
waitForPlayOver.Wait()
<-time.After(time.Second)
dec.Close()
if err = player.Close(); err != nil {
log.Fatal(err)
}
}
示例3:播放网络音频
package main
import (
"io"
"log"
"net/http"
"os"
"sync"
"time"
"github.com/hajimehoshi/oto"
"github.com/tosone/minimp3"
)
func main() {
var err error
var args = os.Args
if len(args) != 2 {
log.Fatal("Run test like this:\n\n\t./networkAudio.test [mp3url]\n\n")
}
var response *http.Response
if response, err = http.Get(args[1]); err != nil {
log.Fatal(err)
}
var dec *minimp3.Decoder
if dec, err = minimp3.NewDecoder(response.Body); err != nil {
log.Fatal(err)
}
<-dec.Started()
log.Printf("Convert audio sample rate: %d, channels: %d\n", dec.SampleRate, dec.Channels)
var context *oto.Context
if context, err = oto.NewContext(dec.SampleRate, dec.Channels, 2, 4096); err != nil {
log.Fatal(err)
}
var waitForPlayOver = new(sync.WaitGroup)
waitForPlayOver.Add(1)
var player = context.NewPlayer()
go func() {
defer response.Body.Close()
for {
var data = make([]byte, 512)
_, err = dec.Read(data)
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
break
}
player.Write(data)
}
log.Println("over play.")
waitForPlayOver.Done()
}()
waitForPlayOver.Wait()
<-time.After(time.Second)
dec.Close()
player.Close()
}
这些示例展示了如何使用minimp3库来解码和播放MP3音频文件,包括本地文件和网络流。注意这些示例都使用了oto库来处理音频播放。
更多关于golang轻量级MP3解码器插件库minimp3的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang轻量级MP3解码器插件库minimp3的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用minimp3在Go中进行轻量级MP3解码
minimp3是一个极简的MP3解码器实现,非常适合嵌入式系统和资源受限环境。在Go中,我们可以通过cgo来使用这个轻量级解码器。下面我将介绍如何在Go项目中使用minimp3进行MP3解码。
安装与准备
首先,你需要获取minimp3的源代码。可以从官方仓库获取:
git clone https://github.com/lieff/minimp3.git
基本使用方法
下面是一个完整的Go示例,展示如何使用minimp3解码MP3文件:
package main
/*
#cgo CFLAGS: -I./minimp3
#cgo LDFLAGS: -L. -lminimp3
#include "minimp3.h"
#include <stdlib.h>
*/
import "C"
import (
"fmt"
"io/ioutil"
"os"
"unsafe"
)
func main() {
// 读取MP3文件
data, err := ioutil.ReadFile("test.mp3")
if err != nil {
fmt.Println("Error reading file:", err)
return
}
// 初始化解码器
var dec C.mp3dec_t
C.mp3dec_init(&dec)
// 准备解码参数
var frame C.mp3dec_frame_info_t
var pcm [C.MINIMP3_MAX_SAMPLES_PER_FRAME]C.mp3d_sample_t
// 转换为C可用的指针
cData := (*C.uint8_t)(unsafe.Pointer(&data[0]))
dataSize := C.int(len(data))
var offset C.int
var totalSamples int
// 创建输出文件
outFile, err := os.Create("output.raw")
if err != nil {
fmt.Println("Error creating output file:", err)
return
}
defer outFile.Close()
// 解码循环
for offset < dataSize {
samples := C.mp3dec_decode_frame(
&dec,
(*C.uint8_t)(unsafe.Pointer(uintptr(unsafe.Pointer(cData))+uintptr(offset))),
dataSize-offset,
&pcm[0],
&frame,
)
if samples == 0 {
break
}
// 写入解码后的PCM数据
pcmData := (*[1 << 30]byte)(unsafe.Pointer(&pcm[0]))[:int(samples)*int(frame.channels)*2]
if _, err := outFile.Write(pcmData); err != nil {
fmt.Println("Error writing PCM data:", err)
return
}
totalSamples += int(samples)
offset += frame.frame_bytes
}
fmt.Printf("Decoded %d samples\n", totalSamples)
}
更高级的封装
为了更方便地在Go中使用,我们可以创建一个简单的封装:
package minimp3
/*
#cgo CFLAGS: -I./minimp3
#cgo LDFLAGS: -L. -lminimp3
#include "minimp3.h"
#include <stdlib.h>
*/
import "C"
import (
"errors"
"unsafe"
)
type Decoder struct {
dec C.mp3dec_t
info C.mp3dec_frame_info_t
buffer [C.MINIMP3_MAX_SAMPLES_PER_FRAME]C.mp3d_sample_t
}
func NewDecoder() *Decoder {
d := &Decoder{}
C.mp3dec_init(&d.dec)
return d
}
func (d *Decoder) Decode(data []byte) (pcm []int16, samples int, err error) {
if len(data) == 0 {
return nil, 0, errors.New("empty input data")
}
cData := (*C.uint8_t)(unsafe.Pointer(&data[0]))
dataSize := C.int(len(data))
samples = int(C.mp3dec_decode_frame(
&d.dec,
cData,
dataSize,
&d.buffer[0],
&d.info,
))
if samples == 0 {
return nil, 0, errors.New("no samples decoded")
}
pcm = make([]int16, samples*int(d.info.channels))
copy(pcm, (*(*[1 << 30]int16)(unsafe.Pointer(&d.buffer[0]))[:samples*int(d.info.channels)])
return pcm, samples, nil
}
func (d *Decoder) Info() (sampleRate, channels, bitrate int) {
return int(d.info.hz), int(d.info.channels), int(d.info.bitrate_kbps)
}
使用封装后的解码器
package main
import (
"fmt"
"io/ioutil"
"os"
"your/path/to/minimp3"
)
func main() {
// 读取MP3文件
data, err := ioutil.ReadFile("test.mp3")
if err != nil {
fmt.Println("Error reading file:", err)
return
}
decoder := minimp3.NewDecoder()
// 创建输出文件
outFile, err := os.Create("output.raw")
if err != nil {
fmt.Println("Error creating output file:", err)
return
}
defer outFile.Close()
var offset int
var totalSamples int
for offset < len(data) {
pcm, samples, err := decoder.Decode(data[offset:])
if err != nil {
fmt.Println("Decoding error:", err)
break
}
if samples == 0 {
break
}
// 写入PCM数据
if _, err := outFile.Write(int16ToBytes(pcm)); err != nil {
fmt.Println("Error writing PCM data:", err)
return
}
totalSamples += samples
offset += int(decoder.info.frame_bytes)
}
fmt.Printf("Decoded %d samples, sample rate: %d, channels: %d\n",
totalSamples, decoder.Info())
}
func int16ToBytes(pcm []int16) []byte {
b := make([]byte, len(pcm)*2)
for i, v := range pcm {
b[i*2] = byte(v)
b[i*2+1] = byte(v >> 8)
}
return b
}
性能与注意事项
- 性能:minimp3非常轻量,解码速度很快,适合实时音频处理
- 内存:内存占用极小,没有动态内存分配
- 功能:只支持MPEG1和MPEG2音频层3(MP3)格式
- 线程安全:解码器状态不是线程安全的,每个goroutine应该有自己的解码器实例
minimp3是一个出色的轻量级MP3解码解决方案,特别适合需要高效解码而不需要完整音频框架的Go应用程序。