1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
/*
* Copyright (C) 2014 Andrew Comminos
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package se.lublin.humla.audio.encoder;
import com.googlecode.javacpp.IntPointer;
import com.googlecode.javacpp.Pointer;
import se.lublin.humla.audio.javacpp.CELT7;
import se.lublin.humla.exception.NativeAudioException;
import se.lublin.humla.net.PacketBuffer;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
/**
* Created by andrew on 08/12/14.
*/
public class CELT7Encoder implements IEncoder {
private final byte[][] mBuffer;
private final int[] mPacketLengths;
private final int mBufferSize;
private final int mFramesPerPacket;
private int mBufferedFrames;
private boolean mReady;
private Pointer mMode;
private Pointer mState;
public CELT7Encoder(int sampleRate, int frameSize, int channels,
int framesPerPacket, int bitrate, int maxBufferSize)
throws NativeAudioException {
mFramesPerPacket = framesPerPacket;
mBufferSize = Math.min(maxBufferSize, bitrate / 800);
mBuffer = new byte[framesPerPacket][mBufferSize];
mPacketLengths = new int[framesPerPacket];
mBufferedFrames = 0;
IntPointer error = new IntPointer(1);
error.put(0);
mMode = CELT7.celt_mode_create(sampleRate, frameSize, error);
if(error.get() < 0) throw new NativeAudioException("CELT 0.7.0 encoder initialization failed with error: "+error.get());
mState = CELT7.celt_encoder_create(mMode, channels, error);
if(error.get() < 0) throw new NativeAudioException("CELT 0.7.0 encoder initialization failed with error: "+error.get());
CELT7.celt_encoder_ctl(mState, CELT7.CELT_SET_PREDICTION_REQUEST, 0);
CELT7.celt_encoder_ctl(mState, CELT7.CELT_SET_VBR_RATE_REQUEST, bitrate);
}
@Override
public int encode(short[] input, int inputSize) throws NativeAudioException {
if (mBufferedFrames >= mFramesPerPacket) {
throw new BufferOverflowException();
}
int result = CELT7.celt_encode(mState, input, null, mBuffer[mBufferedFrames], mBufferSize);
if(result < 0) throw new NativeAudioException("CELT 0.7.0 encoding failed with error: "
+ result);
mPacketLengths[mBufferedFrames] = result;
mBufferedFrames++;
if (mBufferedFrames >= mFramesPerPacket)
mReady = true;
return result;
}
@Override
public int getBufferedFrames() {
return mBufferedFrames;
}
@Override
public boolean isReady() {
return mReady && mBufferedFrames > 0;
}
@Override
public void getEncodedData(PacketBuffer packetBuffer) throws BufferUnderflowException {
if (!mReady)
throw new BufferUnderflowException();
for (int x = 0; x < mBufferedFrames; x++) {
byte[] frame = mBuffer[x];
int length = mPacketLengths[x];
int head = length;
if(x < mBufferedFrames - 1)
head |= 0x80;
packetBuffer.append(head);
packetBuffer.append(frame, length);
}
mBufferedFrames = 0;
mReady = false;
}
@Override
public void terminate() throws NativeAudioException {
mReady = true;
}
@Override
public void destroy() {
CELT7.celt_encoder_destroy(mState);
CELT7.celt_mode_destroy(mMode);
}
}
|