parent
1a73f8e027
commit
c668a359a5
@ -1,340 +0,0 @@ |
|||||||
package com.frank.ffmpeg.mp3; |
|
||||||
|
|
||||||
import android.annotation.TargetApi; |
|
||||||
import android.media.MediaCodec; |
|
||||||
import android.media.MediaCodec.BufferInfo; |
|
||||||
import android.media.MediaExtractor; |
|
||||||
import android.media.MediaFormat; |
|
||||||
import android.os.Build; |
|
||||||
import android.util.Log; |
|
||||||
|
|
||||||
import java.io.BufferedOutputStream; |
|
||||||
import java.io.File; |
|
||||||
import java.io.FileOutputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.nio.ByteBuffer; |
|
||||||
import java.nio.ByteOrder; |
|
||||||
import java.nio.ShortBuffer; |
|
||||||
import java.util.concurrent.BlockingDeque; |
|
||||||
import java.util.concurrent.LinkedBlockingDeque; |
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) |
|
||||||
public class Mp3Converter { |
|
||||||
|
|
||||||
private final static String TAG = Mp3Converter.class.getSimpleName(); |
|
||||||
|
|
||||||
private MediaCodec mMediaCodec; |
|
||||||
private MediaExtractor mediaExtractor; |
|
||||||
private BufferInfo bufferInfo; |
|
||||||
private ByteBuffer[] rawInputBuffers; |
|
||||||
private ByteBuffer[] encodedOutputBuffers; |
|
||||||
private int inSampleRate; |
|
||||||
private int channels; |
|
||||||
|
|
||||||
private final static int DEFAULT_QUEUE_SIZE = 512; |
|
||||||
private BlockingDeque<BufferEncoded> writeQueue = new LinkedBlockingDeque<>(DEFAULT_QUEUE_SIZE); |
|
||||||
private BlockingDeque<BufferDecoded> encodeQueue = new LinkedBlockingDeque<>(DEFAULT_QUEUE_SIZE); |
|
||||||
private byte[] mp3buf; |
|
||||||
|
|
||||||
private boolean decodeFinished; |
|
||||||
private boolean encodeFinished; |
|
||||||
|
|
||||||
private long readSize; |
|
||||||
private long decodeSize; |
|
||||||
private long encodeSize; |
|
||||||
|
|
||||||
private Mp3Lame mp3Lame; |
|
||||||
private WriteThread writeThread; |
|
||||||
private EncodeThread encodeThread; |
|
||||||
private long lastPts; |
|
||||||
|
|
||||||
private class BufferDecoded { |
|
||||||
int channels; |
|
||||||
short[] leftBuffer; |
|
||||||
short[] rightBuffer; |
|
||||||
short[] pcm; |
|
||||||
long pts; |
|
||||||
} |
|
||||||
|
|
||||||
private class BufferEncoded { |
|
||||||
byte[] buffer; |
|
||||||
int length; |
|
||||||
} |
|
||||||
|
|
||||||
private class WriteThread extends Thread { |
|
||||||
|
|
||||||
private String mp3Path; |
|
||||||
private FileOutputStream fos; |
|
||||||
private BufferedOutputStream bos; |
|
||||||
|
|
||||||
WriteThread(String path) { |
|
||||||
super(); |
|
||||||
mp3Path = path; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void run() { |
|
||||||
try { |
|
||||||
Log.i(TAG, "WriteThread start"); |
|
||||||
|
|
||||||
fos = new FileOutputStream(new File(mp3Path)); |
|
||||||
bos = new BufferedOutputStream(fos, 200 * 1024); |
|
||||||
|
|
||||||
while (true) { |
|
||||||
if (encodeFinished && writeQueue.size() == 0) { |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
BufferEncoded buffer = null; |
|
||||||
try { |
|
||||||
buffer = writeQueue.take(); |
|
||||||
} catch (InterruptedException e) { |
|
||||||
Log.e(TAG, "WriteThread InterruptedException=" + e.toString()); |
|
||||||
} |
|
||||||
|
|
||||||
if(buffer != null) { |
|
||||||
bos.write(buffer.buffer, 0, buffer.length); |
|
||||||
} |
|
||||||
} |
|
||||||
bos.flush(); |
|
||||||
bos.close(); |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} finally { |
|
||||||
try { |
|
||||||
bos.flush(); |
|
||||||
bos.close(); |
|
||||||
} catch (IOException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Log.i(TAG, "WriteThread end"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private class EncodeThread extends Thread { |
|
||||||
@Override |
|
||||||
public void run() { |
|
||||||
Log.i(TAG, "EncodeThread start"); |
|
||||||
|
|
||||||
while (true) { |
|
||||||
if (decodeFinished && encodeQueue.size() == 0) { |
|
||||||
break; |
|
||||||
} |
|
||||||
BufferDecoded buffer = null; |
|
||||||
try { |
|
||||||
buffer = encodeQueue.take(); |
|
||||||
} catch (InterruptedException e) { |
|
||||||
Log.e(TAG, "EncodeThread InterruptedException=" + e.toString()); |
|
||||||
} |
|
||||||
if (buffer != null) { |
|
||||||
encodeToMp3(buffer); |
|
||||||
} |
|
||||||
} |
|
||||||
encodeFinished = true; |
|
||||||
|
|
||||||
writeThread.interrupt(); |
|
||||||
|
|
||||||
Log.i(TAG, "EncodeThread end"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private class DecodeThread extends Thread { |
|
||||||
@Override |
|
||||||
public void run() { |
|
||||||
long startTime = System.currentTimeMillis(); |
|
||||||
try { |
|
||||||
Log.i(TAG, "DecodeThread start"); |
|
||||||
|
|
||||||
while (true) { |
|
||||||
int outputBufIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, -1); |
|
||||||
if (outputBufIndex >= 0) { |
|
||||||
ByteBuffer buffer = encodedOutputBuffers[outputBufIndex]; |
|
||||||
decodeSize += bufferInfo.size; |
|
||||||
ShortBuffer shortBuffer = buffer.order(ByteOrder.nativeOrder()).asShortBuffer(); |
|
||||||
|
|
||||||
short[] leftBuffer = null; |
|
||||||
short[] rightBuffer = null; |
|
||||||
short[] pcm = null; |
|
||||||
|
|
||||||
if (channels == 2) { |
|
||||||
pcm = new short[shortBuffer.remaining()]; |
|
||||||
shortBuffer.get(pcm); |
|
||||||
} else { |
|
||||||
leftBuffer = new short[shortBuffer.remaining()]; |
|
||||||
rightBuffer = leftBuffer; |
|
||||||
shortBuffer.get(leftBuffer); |
|
||||||
Log.e(TAG, "single channel leftBuffer.length = " + leftBuffer.length); |
|
||||||
} |
|
||||||
|
|
||||||
buffer.clear(); |
|
||||||
|
|
||||||
BufferDecoded bufferDecoded = new BufferDecoded(); |
|
||||||
bufferDecoded.leftBuffer = leftBuffer; |
|
||||||
bufferDecoded.rightBuffer = rightBuffer; |
|
||||||
bufferDecoded.pcm = pcm; |
|
||||||
bufferDecoded.channels = channels; |
|
||||||
bufferDecoded.pts = bufferInfo.presentationTimeUs; |
|
||||||
encodeQueue.put(bufferDecoded); |
|
||||||
|
|
||||||
mMediaCodec.releaseOutputBuffer(outputBufIndex, false); |
|
||||||
|
|
||||||
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { |
|
||||||
Log.e(TAG, "DecodeThread get BUFFER_FLAG_END_OF_STREAM"); |
|
||||||
decodeFinished = true; |
|
||||||
break; |
|
||||||
} |
|
||||||
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { |
|
||||||
encodedOutputBuffers = mMediaCodec.getOutputBuffers(); |
|
||||||
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
|
||||||
final MediaFormat oformat = mMediaCodec.getOutputFormat(); |
|
||||||
Log.d(TAG, "Output format has changed to " + oformat); |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
|
|
||||||
encodeThread.interrupt(); |
|
||||||
long endTime = System.currentTimeMillis(); |
|
||||||
Log.i(TAG, "DecodeThread finished time=" + (endTime - startTime) / 1000); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void convertToMp3(String srcPath, String mp3Path) { |
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis(); |
|
||||||
long endTime; |
|
||||||
|
|
||||||
encodeThread = new EncodeThread(); |
|
||||||
writeThread = new WriteThread(mp3Path); |
|
||||||
DecodeThread decodeThread = new DecodeThread(); |
|
||||||
|
|
||||||
encodeThread.start(); |
|
||||||
writeThread.start(); |
|
||||||
prepareDecode(srcPath); |
|
||||||
decodeThread.start(); |
|
||||||
readSampleData(); |
|
||||||
|
|
||||||
try { |
|
||||||
writeThread.join(); |
|
||||||
} catch (InterruptedException e) { |
|
||||||
Log.e(TAG, "convertToMp3 InterruptedException=" + e.toString()); |
|
||||||
} |
|
||||||
|
|
||||||
double mReadSize = readSize / 1024.0 / 1024.0; |
|
||||||
double mDecodeSize = decodeSize / 1024.0 / 1024.0; |
|
||||||
double mEncodeSize = encodeSize / 1024.0 / 1024.0; |
|
||||||
Log.i(TAG, "readSize=" + mReadSize + ", decodeSize=" + mDecodeSize + ",encodeSize=" + mEncodeSize); |
|
||||||
|
|
||||||
endTime = System.currentTimeMillis(); |
|
||||||
Log.i(TAG, "convertToMp3 finish time=" + (endTime - startTime) / 1000); |
|
||||||
} |
|
||||||
|
|
||||||
private void prepareDecode(String path) { |
|
||||||
try { |
|
||||||
mediaExtractor = new MediaExtractor(); |
|
||||||
mediaExtractor.setDataSource(path); |
|
||||||
for (int i = 0; i < mediaExtractor.getTrackCount(); i++) { |
|
||||||
MediaFormat mMediaFormat = mediaExtractor.getTrackFormat(i); |
|
||||||
Log.i(TAG, "prepareDecode get mMediaFormat=" + mMediaFormat); |
|
||||||
|
|
||||||
String mime = mMediaFormat.getString(MediaFormat.KEY_MIME); |
|
||||||
if (mime.startsWith("audio")) { |
|
||||||
mMediaCodec = MediaCodec.createDecoderByType(mime); |
|
||||||
mMediaCodec.configure(mMediaFormat, null, null, 0); |
|
||||||
mediaExtractor.selectTrack(i); |
|
||||||
inSampleRate = mMediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE); |
|
||||||
channels = mMediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
mMediaCodec.start(); |
|
||||||
|
|
||||||
bufferInfo = new BufferInfo(); |
|
||||||
rawInputBuffers = mMediaCodec.getInputBuffers(); |
|
||||||
encodedOutputBuffers = mMediaCodec.getOutputBuffers(); |
|
||||||
Log.i(TAG, "--channel=" + channels + "--sampleRate=" + inSampleRate); |
|
||||||
|
|
||||||
mp3Lame = new Mp3LameBuilder() |
|
||||||
.setInSampleRate(inSampleRate) |
|
||||||
.setOutChannels(channels) |
|
||||||
.setOutBitrate(128) |
|
||||||
.setOutSampleRate(inSampleRate) |
|
||||||
.setQuality(9) |
|
||||||
.setVbrMode(Mp3LameBuilder.VbrMode.VBR_MTRH) |
|
||||||
.build(); |
|
||||||
|
|
||||||
} catch (IOException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void readSampleData() { |
|
||||||
boolean rawInputEOS = false; |
|
||||||
|
|
||||||
while (!rawInputEOS) { |
|
||||||
for (int i = 0; i < rawInputBuffers.length; i++) { |
|
||||||
int inputBufIndex = mMediaCodec.dequeueInputBuffer(-1); |
|
||||||
if (inputBufIndex >= 0) { |
|
||||||
ByteBuffer buffer = rawInputBuffers[inputBufIndex]; |
|
||||||
int sampleSize = mediaExtractor.readSampleData(buffer, 0); |
|
||||||
long presentationTimeUs = 0; |
|
||||||
if (sampleSize < 0) { |
|
||||||
rawInputEOS = true; |
|
||||||
sampleSize = 0; |
|
||||||
} else { |
|
||||||
readSize += sampleSize; |
|
||||||
presentationTimeUs = mediaExtractor.getSampleTime(); |
|
||||||
} |
|
||||||
mMediaCodec.queueInputBuffer(inputBufIndex, 0, |
|
||||||
sampleSize, presentationTimeUs, |
|
||||||
rawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0); |
|
||||||
if (!rawInputEOS) { |
|
||||||
mediaExtractor.advance(); |
|
||||||
} else { |
|
||||||
break; |
|
||||||
} |
|
||||||
} else { |
|
||||||
Log.e(TAG, "wrong inputBufIndex=" + inputBufIndex); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void encodeToMp3(BufferDecoded buffer) { |
|
||||||
|
|
||||||
if (buffer == null || buffer.pts == lastPts) { |
|
||||||
return; |
|
||||||
} |
|
||||||
lastPts = buffer.pts; |
|
||||||
|
|
||||||
int bufferLength = buffer.pcm.length / 2; |
|
||||||
if (mp3buf == null) { |
|
||||||
mp3buf = new byte[(int) (bufferLength * 1.25 + 7200)]; |
|
||||||
} |
|
||||||
if (bufferLength > 0) { |
|
||||||
int bytesEncoded; |
|
||||||
if (channels == 2) { |
|
||||||
bytesEncoded = mp3Lame.encodeBufferInterLeaved(buffer.pcm, bufferLength, mp3buf); |
|
||||||
}else { |
|
||||||
bytesEncoded = mp3Lame.encode(buffer.leftBuffer, buffer.leftBuffer, bufferLength, mp3buf); |
|
||||||
} |
|
||||||
Log.d(TAG, "mp3Lame encodeSize=" + bytesEncoded); |
|
||||||
|
|
||||||
if (bytesEncoded > 0) { |
|
||||||
BufferEncoded be = new BufferEncoded(); |
|
||||||
be.buffer = mp3buf; |
|
||||||
be.length = bytesEncoded; |
|
||||||
try { |
|
||||||
writeQueue.put(be); |
|
||||||
} catch (InterruptedException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
encodeSize += bytesEncoded; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,335 @@ |
|||||||
|
package com.frank.ffmpeg.mp3 |
||||||
|
|
||||||
|
import android.annotation.TargetApi |
||||||
|
import android.media.MediaCodec |
||||||
|
import android.media.MediaCodec.BufferInfo |
||||||
|
import android.media.MediaExtractor |
||||||
|
import android.media.MediaFormat |
||||||
|
import android.os.Build |
||||||
|
import android.util.Log |
||||||
|
|
||||||
|
import java.io.BufferedOutputStream |
||||||
|
import java.io.File |
||||||
|
import java.io.FileOutputStream |
||||||
|
import java.io.IOException |
||||||
|
import java.nio.ByteBuffer |
||||||
|
import java.nio.ByteOrder |
||||||
|
import java.util.concurrent.LinkedBlockingDeque |
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) |
||||||
|
class Mp3Converter { |
||||||
|
|
||||||
|
private var mMediaCodec: MediaCodec? = null |
||||||
|
private var mediaExtractor: MediaExtractor? = null |
||||||
|
private var bufferInfo: BufferInfo? = null |
||||||
|
private var rawInputBuffers: Array<ByteBuffer>? = null |
||||||
|
private var encodedOutputBuffers: Array<ByteBuffer>? = null |
||||||
|
private var inSampleRate: Int = 0 |
||||||
|
private var channels: Int = 0 |
||||||
|
private val writeQueue = LinkedBlockingDeque<BufferEncoded>(DEFAULT_QUEUE_SIZE) |
||||||
|
private val encodeQueue = LinkedBlockingDeque<BufferDecoded>(DEFAULT_QUEUE_SIZE) |
||||||
|
private var mp3buf: ByteArray? = null |
||||||
|
|
||||||
|
private var decodeFinished: Boolean = false |
||||||
|
private var encodeFinished: Boolean = false |
||||||
|
|
||||||
|
private var readSize: Long = 0 |
||||||
|
private var decodeSize: Long = 0 |
||||||
|
private var encodeSize: Long = 0 |
||||||
|
|
||||||
|
private var mp3Lame: Mp3Lame? = null |
||||||
|
private var writeThread: WriteThread? = null |
||||||
|
private var encodeThread: EncodeThread? = null |
||||||
|
private var lastPts: Long = 0 |
||||||
|
|
||||||
|
private inner class BufferDecoded { |
||||||
|
internal var channels: Int = 0 |
||||||
|
internal var leftBuffer: ShortArray? = null |
||||||
|
internal var rightBuffer: ShortArray? = null |
||||||
|
internal var pcm: ShortArray? = null |
||||||
|
internal var pts: Long = 0 |
||||||
|
} |
||||||
|
|
||||||
|
private inner class BufferEncoded { |
||||||
|
internal var buffer: ByteArray? = null |
||||||
|
internal var length: Int = 0 |
||||||
|
} |
||||||
|
|
||||||
|
private inner class WriteThread internal constructor(private val mp3Path: String) : Thread() { |
||||||
|
private var fos: FileOutputStream? = null |
||||||
|
private var bos: BufferedOutputStream? = null |
||||||
|
|
||||||
|
override fun run() { |
||||||
|
try { |
||||||
|
Log.i(TAG, "WriteThread start") |
||||||
|
|
||||||
|
fos = FileOutputStream(File(mp3Path)) |
||||||
|
bos = BufferedOutputStream(fos, 200 * 1024) |
||||||
|
|
||||||
|
while (true) { |
||||||
|
if (encodeFinished && writeQueue.size == 0) { |
||||||
|
break |
||||||
|
} |
||||||
|
|
||||||
|
var buffer: BufferEncoded? = null |
||||||
|
try { |
||||||
|
buffer = writeQueue.take() |
||||||
|
} catch (e: InterruptedException) { |
||||||
|
Log.e(TAG, "WriteThread InterruptedException=$e") |
||||||
|
} |
||||||
|
|
||||||
|
if (buffer != null) { |
||||||
|
bos!!.write(buffer.buffer, 0, buffer.length) |
||||||
|
} |
||||||
|
} |
||||||
|
bos!!.flush() |
||||||
|
bos!!.close() |
||||||
|
} catch (e: Exception) { |
||||||
|
e.printStackTrace() |
||||||
|
} finally { |
||||||
|
try { |
||||||
|
bos!!.flush() |
||||||
|
bos!!.close() |
||||||
|
} catch (e: IOException) { |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Log.i(TAG, "WriteThread end") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private inner class EncodeThread : Thread() { |
||||||
|
override fun run() { |
||||||
|
Log.i(TAG, "EncodeThread start") |
||||||
|
|
||||||
|
while (true) { |
||||||
|
if (decodeFinished && encodeQueue.size == 0) { |
||||||
|
break |
||||||
|
} |
||||||
|
var buffer: BufferDecoded? = null |
||||||
|
try { |
||||||
|
buffer = encodeQueue.take() |
||||||
|
} catch (e: InterruptedException) { |
||||||
|
Log.e(TAG, "EncodeThread InterruptedException=$e") |
||||||
|
} |
||||||
|
|
||||||
|
if (buffer != null) { |
||||||
|
encodeToMp3(buffer) |
||||||
|
} |
||||||
|
} |
||||||
|
encodeFinished = true |
||||||
|
|
||||||
|
writeThread!!.interrupt() |
||||||
|
|
||||||
|
Log.i(TAG, "EncodeThread end") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private inner class DecodeThread : Thread() { |
||||||
|
override fun run() { |
||||||
|
val startTime = System.currentTimeMillis() |
||||||
|
try { |
||||||
|
Log.i(TAG, "DecodeThread start") |
||||||
|
|
||||||
|
while (true) { |
||||||
|
val outputBufIndex = mMediaCodec!!.dequeueOutputBuffer(bufferInfo!!, -1) |
||||||
|
if (outputBufIndex >= 0) { |
||||||
|
val buffer = encodedOutputBuffers!![outputBufIndex] |
||||||
|
decodeSize += bufferInfo!!.size.toLong() |
||||||
|
val shortBuffer = buffer.order(ByteOrder.nativeOrder()).asShortBuffer() |
||||||
|
|
||||||
|
var leftBuffer: ShortArray? = null |
||||||
|
var rightBuffer: ShortArray? = null |
||||||
|
var pcm: ShortArray? = null |
||||||
|
|
||||||
|
if (channels == 2) { |
||||||
|
pcm = ShortArray(shortBuffer.remaining()) |
||||||
|
shortBuffer.get(pcm) |
||||||
|
} else { |
||||||
|
leftBuffer = ShortArray(shortBuffer.remaining()) |
||||||
|
rightBuffer = leftBuffer |
||||||
|
shortBuffer.get(leftBuffer) |
||||||
|
Log.e(TAG, "single channel leftBuffer.length = " + leftBuffer.size) |
||||||
|
} |
||||||
|
|
||||||
|
buffer.clear() |
||||||
|
|
||||||
|
val bufferDecoded = BufferDecoded() |
||||||
|
bufferDecoded.leftBuffer = leftBuffer |
||||||
|
bufferDecoded.rightBuffer = rightBuffer |
||||||
|
bufferDecoded.pcm = pcm |
||||||
|
bufferDecoded.channels = channels |
||||||
|
bufferDecoded.pts = bufferInfo!!.presentationTimeUs |
||||||
|
encodeQueue.put(bufferDecoded) |
||||||
|
|
||||||
|
mMediaCodec!!.releaseOutputBuffer(outputBufIndex, false) |
||||||
|
|
||||||
|
if (bufferInfo!!.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM != 0) { |
||||||
|
Log.e(TAG, "DecodeThread get BUFFER_FLAG_END_OF_STREAM") |
||||||
|
decodeFinished = true |
||||||
|
break |
||||||
|
} |
||||||
|
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { |
||||||
|
encodedOutputBuffers = mMediaCodec!!.outputBuffers |
||||||
|
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
||||||
|
val oformat = mMediaCodec!!.outputFormat |
||||||
|
Log.d(TAG, "Output format has changed to $oformat") |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (e: Exception) { |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
|
||||||
|
encodeThread!!.interrupt() |
||||||
|
val endTime = System.currentTimeMillis() |
||||||
|
Log.i(TAG, "DecodeThread finished time=" + (endTime - startTime) / 1000) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun convertToMp3(srcPath: String, mp3Path: String) { |
||||||
|
|
||||||
|
val startTime = System.currentTimeMillis() |
||||||
|
val endTime: Long |
||||||
|
|
||||||
|
encodeThread = EncodeThread() |
||||||
|
writeThread = WriteThread(mp3Path) |
||||||
|
val decodeThread = DecodeThread() |
||||||
|
|
||||||
|
encodeThread!!.start() |
||||||
|
writeThread!!.start() |
||||||
|
prepareDecode(srcPath) |
||||||
|
decodeThread.start() |
||||||
|
readSampleData() |
||||||
|
|
||||||
|
try { |
||||||
|
writeThread!!.join() |
||||||
|
} catch (e: InterruptedException) { |
||||||
|
Log.e(TAG, "convertToMp3 InterruptedException=$e") |
||||||
|
} |
||||||
|
|
||||||
|
val mReadSize = readSize.toDouble() / 1024.0 / 1024.0 |
||||||
|
val mDecodeSize = decodeSize.toDouble() / 1024.0 / 1024.0 |
||||||
|
val mEncodeSize = encodeSize.toDouble() / 1024.0 / 1024.0 |
||||||
|
Log.i(TAG, "readSize=$mReadSize, decodeSize=$mDecodeSize,encodeSize=$mEncodeSize") |
||||||
|
|
||||||
|
endTime = System.currentTimeMillis() |
||||||
|
Log.i(TAG, "convertToMp3 finish time=" + (endTime - startTime) / 1000) |
||||||
|
} |
||||||
|
|
||||||
|
private fun prepareDecode(path: String) { |
||||||
|
try { |
||||||
|
mediaExtractor = MediaExtractor() |
||||||
|
mediaExtractor!!.setDataSource(path) |
||||||
|
for (i in 0 until mediaExtractor!!.trackCount) { |
||||||
|
val mMediaFormat = mediaExtractor!!.getTrackFormat(i) |
||||||
|
Log.i(TAG, "prepareDecode get mMediaFormat=$mMediaFormat") |
||||||
|
|
||||||
|
val mime = mMediaFormat.getString(MediaFormat.KEY_MIME) |
||||||
|
if (mime.startsWith("audio")) { |
||||||
|
mMediaCodec = MediaCodec.createDecoderByType(mime) |
||||||
|
mMediaCodec!!.configure(mMediaFormat, null, null, 0) |
||||||
|
mediaExtractor!!.selectTrack(i) |
||||||
|
inSampleRate = mMediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE) |
||||||
|
channels = mMediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT) |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
mMediaCodec!!.start() |
||||||
|
|
||||||
|
bufferInfo = BufferInfo() |
||||||
|
rawInputBuffers = mMediaCodec!!.inputBuffers |
||||||
|
encodedOutputBuffers = mMediaCodec!!.outputBuffers |
||||||
|
Log.i(TAG, "--channel=$channels--sampleRate=$inSampleRate") |
||||||
|
|
||||||
|
mp3Lame = Mp3LameBuilder() |
||||||
|
.setInSampleRate(inSampleRate) |
||||||
|
.setOutChannels(channels) |
||||||
|
.setOutBitrate(128) |
||||||
|
.setOutSampleRate(inSampleRate) |
||||||
|
.setQuality(9) |
||||||
|
.setVbrMode(Mp3LameBuilder.VbrMode.VBR_MTRH) |
||||||
|
.build() |
||||||
|
|
||||||
|
} catch (e: IOException) { |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private fun readSampleData() { |
||||||
|
var rawInputEOS = false |
||||||
|
|
||||||
|
while (!rawInputEOS) { |
||||||
|
for (i in rawInputBuffers!!.indices) { |
||||||
|
val inputBufIndex = mMediaCodec!!.dequeueInputBuffer(-1) |
||||||
|
if (inputBufIndex >= 0) { |
||||||
|
val buffer = rawInputBuffers!![inputBufIndex] |
||||||
|
var sampleSize = mediaExtractor!!.readSampleData(buffer, 0) |
||||||
|
var presentationTimeUs: Long = 0 |
||||||
|
if (sampleSize < 0) { |
||||||
|
rawInputEOS = true |
||||||
|
sampleSize = 0 |
||||||
|
} else { |
||||||
|
readSize += sampleSize.toLong() |
||||||
|
presentationTimeUs = mediaExtractor!!.sampleTime |
||||||
|
} |
||||||
|
mMediaCodec!!.queueInputBuffer(inputBufIndex, 0, |
||||||
|
sampleSize, presentationTimeUs, |
||||||
|
if (rawInputEOS) MediaCodec.BUFFER_FLAG_END_OF_STREAM else 0) |
||||||
|
if (!rawInputEOS) { |
||||||
|
mediaExtractor!!.advance() |
||||||
|
} else { |
||||||
|
break |
||||||
|
} |
||||||
|
} else { |
||||||
|
Log.e(TAG, "wrong inputBufIndex=$inputBufIndex") |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun encodeToMp3(buffer: BufferDecoded?) { |
||||||
|
|
||||||
|
if (buffer == null || buffer.pts == lastPts) { |
||||||
|
return |
||||||
|
} |
||||||
|
lastPts = buffer.pts |
||||||
|
|
||||||
|
val bufferLength = buffer.pcm!!.size / 2 |
||||||
|
if (mp3buf == null) { |
||||||
|
mp3buf = ByteArray((bufferLength * 1.25 + 7200).toInt()) |
||||||
|
} |
||||||
|
if (bufferLength > 0) { |
||||||
|
val bytesEncoded: Int |
||||||
|
if (channels == 2) { |
||||||
|
bytesEncoded = mp3Lame!!.encodeBufferInterLeaved(buffer.pcm!!, bufferLength, mp3buf!!) |
||||||
|
} else { |
||||||
|
bytesEncoded = mp3Lame!!.encode(buffer.leftBuffer!!, buffer.leftBuffer!!, bufferLength, mp3buf!!) |
||||||
|
} |
||||||
|
Log.d(TAG, "mp3Lame encodeSize=$bytesEncoded") |
||||||
|
|
||||||
|
if (bytesEncoded > 0) { |
||||||
|
val be = BufferEncoded() |
||||||
|
be.buffer = mp3buf |
||||||
|
be.length = bytesEncoded |
||||||
|
try { |
||||||
|
writeQueue.put(be) |
||||||
|
} catch (e: InterruptedException) { |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
|
||||||
|
encodeSize += bytesEncoded.toLong() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
private val TAG = Mp3Converter::class.java.simpleName |
||||||
|
|
||||||
|
private const val DEFAULT_QUEUE_SIZE = 512 |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,71 +0,0 @@ |
|||||||
package com.frank.ffmpeg.mp3; |
|
||||||
|
|
||||||
import com.frank.ffmpeg.AudioPlayer; |
|
||||||
|
|
||||||
public class Mp3Lame { |
|
||||||
|
|
||||||
public Mp3Lame() { |
|
||||||
AudioPlayer.lameInitDefault(); |
|
||||||
} |
|
||||||
|
|
||||||
Mp3Lame(Mp3LameBuilder builder) { |
|
||||||
initialize(builder); |
|
||||||
} |
|
||||||
|
|
||||||
private void initialize(Mp3LameBuilder builder) { |
|
||||||
AudioPlayer.lameInit(builder.inSampleRate, builder.outChannel, builder.outSampleRate, |
|
||||||
builder.outBitrate, builder.scaleInput, getIntForMode(builder.mode), getIntForVbrMode(builder.vbrMode), builder.quality, builder.vbrQuality, builder.abrMeanBitrate, |
|
||||||
builder.lowPassFreq, builder.highPassFreq, builder.id3tagTitle, builder.id3tagArtist, |
|
||||||
builder.id3tagAlbum, builder.id3tagYear, builder.id3tagComment); |
|
||||||
} |
|
||||||
|
|
||||||
public int encode(short[] buffer_l, short[] buffer_r, |
|
||||||
int samples, byte[] mp3buf) { |
|
||||||
|
|
||||||
return AudioPlayer.lameEncode(buffer_l, buffer_r, samples, mp3buf); |
|
||||||
} |
|
||||||
|
|
||||||
int encodeBufferInterLeaved(short[] pcm, int samples, |
|
||||||
byte[] mp3buf) { |
|
||||||
return AudioPlayer.encodeBufferInterleaved(pcm, samples, mp3buf); |
|
||||||
} |
|
||||||
|
|
||||||
public int flush(byte[] mp3buf) { |
|
||||||
return AudioPlayer.lameFlush(mp3buf); |
|
||||||
} |
|
||||||
|
|
||||||
public void close() { |
|
||||||
AudioPlayer.lameClose(); |
|
||||||
} |
|
||||||
|
|
||||||
private static int getIntForMode(Mp3LameBuilder.Mode mode) { |
|
||||||
switch (mode) { |
|
||||||
case STEREO: |
|
||||||
return 0; |
|
||||||
case JSTEREO: |
|
||||||
return 1; |
|
||||||
case MONO: |
|
||||||
return 3; |
|
||||||
case DEFAULT: |
|
||||||
return 4; |
|
||||||
} |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
private static int getIntForVbrMode(Mp3LameBuilder.VbrMode mode) { |
|
||||||
switch (mode) { |
|
||||||
case VBR_OFF: |
|
||||||
return 0; |
|
||||||
case VBR_RH: |
|
||||||
return 2; |
|
||||||
case VBR_ABR: |
|
||||||
return 3; |
|
||||||
case VBR_MTRH: |
|
||||||
return 4; |
|
||||||
case VBR_DEFAUT: |
|
||||||
return 6; |
|
||||||
} |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,60 @@ |
|||||||
|
package com.frank.ffmpeg.mp3 |
||||||
|
|
||||||
|
import com.frank.ffmpeg.AudioPlayer |
||||||
|
|
||||||
|
class Mp3Lame { |
||||||
|
|
||||||
|
constructor() { |
||||||
|
AudioPlayer.lameInitDefault() |
||||||
|
} |
||||||
|
|
||||||
|
internal constructor(builder: Mp3LameBuilder) { |
||||||
|
initialize(builder) |
||||||
|
} |
||||||
|
|
||||||
|
private fun initialize(builder: Mp3LameBuilder) { |
||||||
|
AudioPlayer.lameInit(builder.inSampleRate, builder.outChannel, builder.outSampleRate, |
||||||
|
builder.outBitrate, builder.scaleInput, getIntForMode(builder.mode), getIntForVbrMode(builder.vbrMode), builder.quality, builder.vbrQuality, builder.abrMeanBitrate, |
||||||
|
builder.lowPassFreq, builder.highPassFreq, builder.id3tagTitle, builder.id3tagArtist, |
||||||
|
builder.id3tagAlbum, builder.id3tagYear, builder.id3tagComment) |
||||||
|
} |
||||||
|
|
||||||
|
fun encode(buffer_l: ShortArray, buffer_r: ShortArray, |
||||||
|
samples: Int, mp3buf: ByteArray): Int { |
||||||
|
|
||||||
|
return AudioPlayer.lameEncode(buffer_l, buffer_r, samples, mp3buf) |
||||||
|
} |
||||||
|
|
||||||
|
internal fun encodeBufferInterLeaved(pcm: ShortArray, samples: Int, |
||||||
|
mp3buf: ByteArray): Int { |
||||||
|
return AudioPlayer.encodeBufferInterleaved(pcm, samples, mp3buf) |
||||||
|
} |
||||||
|
|
||||||
|
fun flush(mp3buf: ByteArray): Int { |
||||||
|
return AudioPlayer.lameFlush(mp3buf) |
||||||
|
} |
||||||
|
|
||||||
|
fun close() { |
||||||
|
AudioPlayer.lameClose() |
||||||
|
} |
||||||
|
|
||||||
|
private fun getIntForMode(mode: Mp3LameBuilder.Mode): Int { |
||||||
|
return when (mode) { |
||||||
|
Mp3LameBuilder.Mode.STEREO -> 0 |
||||||
|
Mp3LameBuilder.Mode.JSTEREO -> 1 |
||||||
|
Mp3LameBuilder.Mode.MONO -> 3 |
||||||
|
Mp3LameBuilder.Mode.DEFAULT -> 4 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun getIntForVbrMode(mode: Mp3LameBuilder.VbrMode): Int { |
||||||
|
return when (mode) { |
||||||
|
Mp3LameBuilder.VbrMode.VBR_OFF -> 0 |
||||||
|
Mp3LameBuilder.VbrMode.VBR_RH -> 2 |
||||||
|
Mp3LameBuilder.VbrMode.VBR_ABR -> 3 |
||||||
|
Mp3LameBuilder.VbrMode.VBR_MTRH -> 4 |
||||||
|
Mp3LameBuilder.VbrMode.VBR_DEFAUT -> 6 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,147 +0,0 @@ |
|||||||
package com.frank.ffmpeg.mp3; |
|
||||||
|
|
||||||
public class Mp3LameBuilder { |
|
||||||
|
|
||||||
|
|
||||||
public enum Mode { |
|
||||||
STEREO, JSTEREO, MONO, DEFAULT |
|
||||||
} |
|
||||||
|
|
||||||
public enum VbrMode { |
|
||||||
VBR_OFF, VBR_RH, VBR_MTRH, VBR_ABR, VBR_DEFAUT |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
int inSampleRate; |
|
||||||
int outSampleRate; |
|
||||||
int outBitrate; |
|
||||||
int outChannel; |
|
||||||
public int quality; |
|
||||||
int vbrQuality; |
|
||||||
int abrMeanBitrate; |
|
||||||
int lowPassFreq; |
|
||||||
int highPassFreq; |
|
||||||
float scaleInput; |
|
||||||
Mode mode; |
|
||||||
VbrMode vbrMode; |
|
||||||
|
|
||||||
String id3tagTitle; |
|
||||||
String id3tagArtist; |
|
||||||
String id3tagAlbum; |
|
||||||
String id3tagComment; |
|
||||||
String id3tagYear; |
|
||||||
|
|
||||||
Mp3LameBuilder() { |
|
||||||
|
|
||||||
this.id3tagTitle = null; |
|
||||||
this.id3tagAlbum = null; |
|
||||||
this.id3tagArtist = null; |
|
||||||
this.id3tagComment = null; |
|
||||||
this.id3tagYear = null; |
|
||||||
|
|
||||||
this.inSampleRate = 44100; |
|
||||||
this.outSampleRate = 0; |
|
||||||
this.outChannel = 2; |
|
||||||
this.outBitrate = 128; |
|
||||||
this.scaleInput = 1; |
|
||||||
|
|
||||||
this.quality = 5; |
|
||||||
this.mode = Mode.DEFAULT; |
|
||||||
this.vbrMode = VbrMode.VBR_OFF; |
|
||||||
this.vbrQuality = 5; |
|
||||||
this.abrMeanBitrate = 128; |
|
||||||
|
|
||||||
this.lowPassFreq = 0; |
|
||||||
this.highPassFreq = 0; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setQuality(int quality) { |
|
||||||
this.quality = quality; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setInSampleRate(int inSampleRate) { |
|
||||||
this.inSampleRate = inSampleRate; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setOutSampleRate(int outSampleRate) { |
|
||||||
this.outSampleRate = outSampleRate; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setOutBitrate(int bitrate) { |
|
||||||
this.outBitrate = bitrate; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setOutChannels(int channels) { |
|
||||||
this.outChannel = channels; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setId3tagTitle(String title) { |
|
||||||
this.id3tagTitle = title; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setId3tagArtist(String artist) { |
|
||||||
this.id3tagArtist = artist; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setId3tagAlbum(String album) { |
|
||||||
this.id3tagAlbum = album; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setId3tagComment(String comment) { |
|
||||||
this.id3tagComment = comment; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setId3tagYear(String year) { |
|
||||||
this.id3tagYear = year; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setScaleInput(float scaleAmount) { |
|
||||||
this.scaleInput = scaleAmount; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setMode(Mode mode) { |
|
||||||
this.mode = mode; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setVbrMode(VbrMode mode) { |
|
||||||
this.vbrMode = mode; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setVbrQuality(int quality) { |
|
||||||
this.vbrQuality = quality; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setAbrMeanBitrate(int bitrate) { |
|
||||||
this.abrMeanBitrate = bitrate; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setLowpassFreqency(int freq) { |
|
||||||
this.lowPassFreq = freq; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3LameBuilder setHighpassFreqency(int freq) { |
|
||||||
this.highPassFreq = freq; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
Mp3Lame build() { |
|
||||||
return new Mp3Lame(this); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,147 @@ |
|||||||
|
package com.frank.ffmpeg.mp3 |
||||||
|
|
||||||
|
class Mp3LameBuilder internal constructor() { |
||||||
|
|
||||||
|
|
||||||
|
internal var inSampleRate: Int = 0 |
||||||
|
internal var outSampleRate: Int = 0 |
||||||
|
internal var outBitrate: Int = 0 |
||||||
|
internal var outChannel: Int = 0 |
||||||
|
var quality: Int = 0 |
||||||
|
internal var vbrQuality: Int = 0 |
||||||
|
internal var abrMeanBitrate: Int = 0 |
||||||
|
internal var lowPassFreq: Int = 0 |
||||||
|
internal var highPassFreq: Int = 0 |
||||||
|
internal var scaleInput: Float = 0.toFloat() |
||||||
|
internal var mode: Mode |
||||||
|
internal var vbrMode: VbrMode |
||||||
|
|
||||||
|
internal var id3tagTitle: String? = null |
||||||
|
internal var id3tagArtist: String? = null |
||||||
|
internal var id3tagAlbum: String? = null |
||||||
|
internal var id3tagComment: String? = null |
||||||
|
internal var id3tagYear: String? = null |
||||||
|
|
||||||
|
|
||||||
|
enum class Mode { |
||||||
|
STEREO, JSTEREO, MONO, DEFAULT |
||||||
|
} |
||||||
|
|
||||||
|
enum class VbrMode { |
||||||
|
VBR_OFF, VBR_RH, VBR_MTRH, VBR_ABR, VBR_DEFAUT |
||||||
|
} |
||||||
|
|
||||||
|
init { |
||||||
|
|
||||||
|
this.id3tagTitle = null |
||||||
|
this.id3tagAlbum = null |
||||||
|
this.id3tagArtist = null |
||||||
|
this.id3tagComment = null |
||||||
|
this.id3tagYear = null |
||||||
|
|
||||||
|
this.inSampleRate = 44100 |
||||||
|
this.outSampleRate = 0 |
||||||
|
this.outChannel = 2 |
||||||
|
this.outBitrate = 128 |
||||||
|
this.scaleInput = 1f |
||||||
|
|
||||||
|
this.quality = 5 |
||||||
|
this.mode = Mode.DEFAULT |
||||||
|
this.vbrMode = VbrMode.VBR_OFF |
||||||
|
this.vbrQuality = 5 |
||||||
|
this.abrMeanBitrate = 128 |
||||||
|
|
||||||
|
this.lowPassFreq = 0 |
||||||
|
this.highPassFreq = 0 |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setQuality(quality: Int): Mp3LameBuilder { |
||||||
|
this.quality = quality |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setInSampleRate(inSampleRate: Int): Mp3LameBuilder { |
||||||
|
this.inSampleRate = inSampleRate |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setOutSampleRate(outSampleRate: Int): Mp3LameBuilder { |
||||||
|
this.outSampleRate = outSampleRate |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setOutBitrate(bitrate: Int): Mp3LameBuilder { |
||||||
|
this.outBitrate = bitrate |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setOutChannels(channels: Int): Mp3LameBuilder { |
||||||
|
this.outChannel = channels |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setId3tagTitle(title: String): Mp3LameBuilder { |
||||||
|
this.id3tagTitle = title |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setId3tagArtist(artist: String): Mp3LameBuilder { |
||||||
|
this.id3tagArtist = artist |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setId3tagAlbum(album: String): Mp3LameBuilder { |
||||||
|
this.id3tagAlbum = album |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setId3tagComment(comment: String): Mp3LameBuilder { |
||||||
|
this.id3tagComment = comment |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setId3tagYear(year: String): Mp3LameBuilder { |
||||||
|
this.id3tagYear = year |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setScaleInput(scaleAmount: Float): Mp3LameBuilder { |
||||||
|
this.scaleInput = scaleAmount |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setMode(mode: Mode): Mp3LameBuilder { |
||||||
|
this.mode = mode |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setVbrMode(mode: VbrMode): Mp3LameBuilder { |
||||||
|
this.vbrMode = mode |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setVbrQuality(quality: Int): Mp3LameBuilder { |
||||||
|
this.vbrQuality = quality |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setAbrMeanBitrate(bitrate: Int): Mp3LameBuilder { |
||||||
|
this.abrMeanBitrate = bitrate |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setLowpassFreqency(freq: Int): Mp3LameBuilder { |
||||||
|
this.lowPassFreq = freq |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun setHighpassFreqency(freq: Int): Mp3LameBuilder { |
||||||
|
this.highPassFreq = freq |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
internal fun build(): Mp3Lame { |
||||||
|
return Mp3Lame(this) |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue