Automatically select best subframe encoding predictor
This commit is contained in:
parent
e1a48c4800
commit
28f458bc53
|
@ -121,16 +121,6 @@ func wav2flac(wavPath string, force bool) error {
|
|||
//break
|
||||
}
|
||||
for _, subframe := range subframes {
|
||||
subHdr := frame.SubHeader{
|
||||
// Specifies the prediction method used to encode the audio sample of the
|
||||
// subframe.
|
||||
Pred: frame.PredVerbatim,
|
||||
// Prediction order used by fixed and FIR linear prediction decoding.
|
||||
Order: 0,
|
||||
// Wasted bits-per-sample.
|
||||
Wasted: 0,
|
||||
}
|
||||
subframe.SubHeader = subHdr
|
||||
subframe.NSamples = n / nchannels
|
||||
subframe.Samples = subframe.Samples[:subframe.NSamples]
|
||||
}
|
||||
|
@ -138,21 +128,6 @@ func wav2flac(wavPath string, force bool) error {
|
|||
subframe := subframes[i%nchannels]
|
||||
subframe.Samples[i/nchannels] = int32(sample)
|
||||
}
|
||||
// Check if the subframe may be encoded as constant; when all samples are
|
||||
// the same.
|
||||
for _, subframe := range subframes {
|
||||
sample := subframe.Samples[0]
|
||||
constant := true
|
||||
for _, s := range subframe.Samples[1:] {
|
||||
if sample != s {
|
||||
constant = false
|
||||
}
|
||||
}
|
||||
if constant {
|
||||
fmt.Println("constant method")
|
||||
subframe.SubHeader.Pred = frame.PredConstant
|
||||
}
|
||||
}
|
||||
|
||||
// Encode FLAC frame.
|
||||
channels, err := getChannels(nchannels)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package flac
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"git.gammaspectra.live/S.O.N.G/flacgo/frame"
|
||||
iobits "git.gammaspectra.live/S.O.N.G/flacgo/internal/bits"
|
||||
"github.com/icza/bitio"
|
||||
|
@ -11,6 +12,25 @@ import (
|
|||
|
||||
// encodeSubframe encodes the given subframe, writing to bw.
|
||||
func encodeSubframe(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe) error {
|
||||
//Select predictor mode
|
||||
predicted := 0
|
||||
subHeader := frame.SubHeader{
|
||||
Pred: frame.PredVerbatim,
|
||||
}
|
||||
|
||||
for i := frame.PredConstant; i < (frame.PredFIR + 1); i++ {
|
||||
shd, estimate := estimateSize(i, hdr, subframe)
|
||||
if estimate > 0 {
|
||||
if predicted == 0 || estimate < predicted {
|
||||
predicted = estimate
|
||||
subHeader = shd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Use best
|
||||
subframe.SubHeader = subHeader
|
||||
|
||||
// Encode subframe header.
|
||||
if err := encodeSubframeHeader(bw, subframe.SubHeader); err != nil {
|
||||
return errutil.Err(err)
|
||||
|
@ -23,7 +43,7 @@ func encodeSubframe(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe
|
|||
return errutil.Err(err)
|
||||
}
|
||||
case frame.PredVerbatim:
|
||||
if err := encodeVerbatimSamples(bw, hdr, subframe.Samples); err != nil {
|
||||
if err := encodeVerbatimSamples(bw, hdr.BlockSize, hdr.BitsPerSample, subframe.Samples); err != nil {
|
||||
return errutil.Err(err)
|
||||
}
|
||||
//case frame.PredFixed:
|
||||
|
@ -40,6 +60,42 @@ func encodeSubframe(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe
|
|||
return nil
|
||||
}
|
||||
|
||||
func estimateSize(pred frame.Pred, hdr frame.Header, subframe *frame.Subframe) (frame.SubHeader, int) {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
bw := bitio.NewWriter(buf)
|
||||
|
||||
switch pred {
|
||||
case frame.PredConstant:
|
||||
if err := encodeConstantSamples(bw, hdr.BitsPerSample, subframe.Samples); err != nil {
|
||||
return frame.SubHeader{}, 0
|
||||
}
|
||||
return frame.SubHeader{
|
||||
Pred: pred,
|
||||
Order: 0,
|
||||
Wasted: 0,
|
||||
}, buf.Len()
|
||||
case frame.PredVerbatim:
|
||||
if err := encodeVerbatimSamples(bw, hdr.BlockSize, hdr.BitsPerSample, subframe.Samples); err != nil {
|
||||
return frame.SubHeader{}, 0
|
||||
}
|
||||
return frame.SubHeader{
|
||||
Pred: pred,
|
||||
Order: 0,
|
||||
Wasted: 0,
|
||||
}, buf.Len()
|
||||
//case frame.PredFixed:
|
||||
// if err := encodeFixedSamples(bw, hdr, subframe.Samples, subframe.Order); err != nil {
|
||||
// return errutil.Err(err)
|
||||
// }
|
||||
//case frame.PredFIR:
|
||||
// if err := encodeFIRSamples(bw, hdr, subframe.Samples, subframe.Order); err != nil {
|
||||
// return errutil.Err(err)
|
||||
// }
|
||||
|
||||
}
|
||||
return frame.SubHeader{}, 0
|
||||
}
|
||||
|
||||
// --- [ Subframe header ] -----------------------------------------------------
|
||||
|
||||
// encodeSubframeHeader encodes the given subframe header, writing to bw.
|
||||
|
@ -113,13 +169,13 @@ func encodeConstantSamples(bw *bitio.Writer, bps byte, samples []int32) error {
|
|||
|
||||
// encodeVerbatimSamples stores the given samples verbatim (uncompressed),
|
||||
// writing to bw.
|
||||
func encodeVerbatimSamples(bw *bitio.Writer, hdr frame.Header, samples []int32) error {
|
||||
func encodeVerbatimSamples(bw *bitio.Writer, blockSize uint16, bps byte, samples []int32) error {
|
||||
// Unencoded subblock; n = frame's bits-per-sample, i = frame's blocksize.
|
||||
if int(hdr.BlockSize) != len(samples) {
|
||||
return errutil.Newf("block size and sample count mismatch; expected %d, got %d", hdr.BlockSize, len(samples))
|
||||
if int(blockSize) != len(samples) {
|
||||
return errutil.Newf("block size and sample count mismatch; expected %d, got %d", blockSize, len(samples))
|
||||
}
|
||||
for _, sample := range samples {
|
||||
if err := bw.WriteBits(uint64(sample), hdr.BitsPerSample); err != nil {
|
||||
if err := bw.WriteBits(uint64(sample), bps); err != nil {
|
||||
return errutil.Err(err)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue