wechatDataBackup/pkg/lame/lame.go
2024-08-26 22:56:29 +08:00

240 lines
4.6 KiB
Go

package lame
// http://www.leidinger.net/lame/doxy/html/lame_8h-source.html
/*
#cgo CFLAGS: -DHAVE_CONFIG_H -I./clame
#cgo LDFLAGS: -lm
#include "lame.h"
*/
import "C"
import (
"runtime"
"unsafe"
)
type Handle *C.struct_lame_global_struct
const (
STEREO = C.STEREO
JOINT_STEREO = C.JOINT_STEREO
DUAL_CHANNEL = C.DUAL_CHANNEL /* LAME doesn't supports this! */
MONO = C.MONO
NOT_SET = C.NOT_SET
MAX_INDICATOR = C.MAX_INDICATOR
BIT_DEPTH = 16
VBR_OFF = C.vbr_off
VBR_RH = C.vbr_rh
VBR_ABR = C.vbr_abr
VBR_MTRH = C.vbr_mtrh
VBR_DEFAULT = C.vbr_default
MAX_FRAME_SIZE = 2880
)
const (
ABR_8 = C.ABR_8
ABR_320 = C.ABR_320
V9 = C.V9
VBR_10 = C.VBR_10
V8 = C.V8
VBR_20 = C.VBR_20
V7 = C.V7
VBR_30 = C.VBR_30
V6 = C.V6
VBR_40 = C.VBR_40
V5 = C.V5
VBR_50 = C.VBR_50
V4 = C.V4
VBR_60 = C.VBR_60
V3 = C.V3
VBR_70 = C.VBR_70
V2 = C.V2
VBR_80 = C.VBR_80
V1 = C.V1
VBR_90 = C.VBR_90
V0 = C.V0
VBR_100 = C.VBR_100
)
type Encoder struct {
handle Handle
remainder []byte
closed bool
}
func Init() *Encoder {
handle := C.lame_init()
encoder := &Encoder{handle, make([]byte, 0), false}
runtime.SetFinalizer(encoder, finalize)
return encoder
}
func (e *Encoder) SetVBR(mode C.vbr_mode) {
C.lame_set_VBR(e.handle, mode)
}
func (e *Encoder) SetVBRAverageBitRate(averageBitRate int) {
C.lame_set_VBR_mean_bitrate_kbps(e.handle, C.int(averageBitRate))
}
func (e *Encoder) SetVBRQuality(quality int) {
C.lame_set_VBR_q(e.handle, C.int(quality))
}
func (e *Encoder) SetLowPassFrequency(frequency int) {
// Frequency in Hz
C.lame_set_lowpassfreq(e.handle, C.int(frequency))
}
func (e *Encoder) SetNumChannels(num int) {
C.lame_set_num_channels(e.handle, C.int(num))
}
func (e *Encoder) SetInSamplerate(sampleRate int) {
C.lame_set_in_samplerate(e.handle, C.int(sampleRate))
}
func (e *Encoder) SetBitrate(bitRate int) {
C.lame_set_brate(e.handle, C.int(bitRate))
}
func (e *Encoder) SetMode(mode C.MPEG_mode) {
C.lame_set_mode(e.handle, mode)
}
func (e *Encoder) SetQuality(quality int) {
C.lame_set_quality(e.handle, C.int(quality))
}
func (e *Encoder) InitId3Tag() {
C.id3tag_init(e.handle)
}
func (e *Encoder) SetWriteId3tagAutomatic(automaticWriteTag int) {
C.lame_set_write_id3tag_automatic(e.handle, C.int(automaticWriteTag))
}
func (e *Encoder) ID3TagAddV2() {
C.id3tag_add_v2(e.handle)
}
func (e *Encoder) SetbWriteVbrTag(writeVbrTag int) {
C.lame_set_bWriteVbrTag(e.handle, C.int(writeVbrTag))
}
func (e *Encoder) GetLametagFrame() []byte {
tagFrame := make([]byte, MAX_FRAME_SIZE)
tagFrameLen := C.lame_get_lametag_frame(e.handle, (*C.uchar)(unsafe.Pointer(&tagFrame[0])), C.size_t(len(tagFrame)))
return tagFrame[0:tagFrameLen]
}
func (e *Encoder) InitParams() int {
retcode := C.lame_init_params(e.handle)
return int(retcode)
}
func (e *Encoder) NumChannels() int {
n := C.lame_get_num_channels(e.handle)
return int(n)
}
func (e *Encoder) Bitrate() int {
br := C.lame_get_brate(e.handle)
return int(br)
}
func (e *Encoder) Mode() int {
m := C.lame_get_mode(e.handle)
return int(m)
}
func (e *Encoder) Quality() int {
q := C.lame_get_quality(e.handle)
return int(q)
}
func (e *Encoder) InSamplerate() int {
sr := C.lame_get_in_samplerate(e.handle)
return int(sr)
}
func (e *Encoder) Encode(buf []byte) []byte {
if len(e.remainder) > 0 {
buf = append(e.remainder, buf...)
}
if len(buf) == 0 {
return make([]byte, 0)
}
blockAlign := BIT_DEPTH / 8 * e.NumChannels()
remainBytes := len(buf) % blockAlign
if remainBytes > 0 {
e.remainder = buf[len(buf)-remainBytes : len(buf)]
buf = buf[0 : len(buf)-remainBytes]
} else {
e.remainder = make([]byte, 0)
}
numSamples := len(buf) / blockAlign
estimatedSize := int(1.25*float64(numSamples) + 7200)
out := make([]byte, estimatedSize)
cBuf := (*C.short)(unsafe.Pointer(&buf[0]))
cOut := (*C.uchar)(unsafe.Pointer(&out[0]))
var bytesOut C.int
if e.NumChannels() == 1 {
bytesOut = C.int(C.lame_encode_buffer(
e.handle,
cBuf,
nil,
C.int(numSamples),
cOut,
C.int(estimatedSize),
))
} else {
bytesOut = C.int(C.lame_encode_buffer_interleaved(
e.handle,
cBuf,
C.int(numSamples),
cOut,
C.int(estimatedSize),
))
}
return out[0:bytesOut]
}
func (e *Encoder) Flush() []byte {
estimatedSize := 7200
out := make([]byte, estimatedSize)
cOut := (*C.uchar)(unsafe.Pointer(&out[0]))
bytesOut := C.int(C.lame_encode_flush(
e.handle,
cOut,
C.int(estimatedSize),
))
return out[0:bytesOut]
}
func (e *Encoder) Close() {
if e.closed {
return
}
C.lame_close(e.handle)
e.closed = true
}
func finalize(e *Encoder) {
e.Close()
}