diff --git a/app/src/main/java/com/frank/ffmpeg/mp3/Mp3Converter.java b/app/src/main/java/com/frank/ffmpeg/mp3/Mp3Converter.java deleted file mode 100644 index 8f4ac13..0000000 --- a/app/src/main/java/com/frank/ffmpeg/mp3/Mp3Converter.java +++ /dev/null @@ -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 writeQueue = new LinkedBlockingDeque<>(DEFAULT_QUEUE_SIZE); - private BlockingDeque 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; - } - } - } - -} diff --git a/app/src/main/java/com/frank/ffmpeg/mp3/Mp3Converter.kt b/app/src/main/java/com/frank/ffmpeg/mp3/Mp3Converter.kt new file mode 100644 index 0000000..cc23403 --- /dev/null +++ b/app/src/main/java/com/frank/ffmpeg/mp3/Mp3Converter.kt @@ -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? = null + private var encodedOutputBuffers: Array? = null + private var inSampleRate: Int = 0 + private var channels: Int = 0 + private val writeQueue = LinkedBlockingDeque(DEFAULT_QUEUE_SIZE) + private val encodeQueue = LinkedBlockingDeque(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 + } + +} diff --git a/app/src/main/java/com/frank/ffmpeg/mp3/Mp3Lame.java b/app/src/main/java/com/frank/ffmpeg/mp3/Mp3Lame.java deleted file mode 100644 index 4dd3730..0000000 --- a/app/src/main/java/com/frank/ffmpeg/mp3/Mp3Lame.java +++ /dev/null @@ -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; - } - -} diff --git a/app/src/main/java/com/frank/ffmpeg/mp3/Mp3Lame.kt b/app/src/main/java/com/frank/ffmpeg/mp3/Mp3Lame.kt new file mode 100644 index 0000000..0bcb07e --- /dev/null +++ b/app/src/main/java/com/frank/ffmpeg/mp3/Mp3Lame.kt @@ -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 + } + } + +} diff --git a/app/src/main/java/com/frank/ffmpeg/mp3/Mp3LameBuilder.java b/app/src/main/java/com/frank/ffmpeg/mp3/Mp3LameBuilder.java deleted file mode 100644 index 5ff5ef2..0000000 --- a/app/src/main/java/com/frank/ffmpeg/mp3/Mp3LameBuilder.java +++ /dev/null @@ -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); - } - -} diff --git a/app/src/main/java/com/frank/ffmpeg/mp3/Mp3LameBuilder.kt b/app/src/main/java/com/frank/ffmpeg/mp3/Mp3LameBuilder.kt new file mode 100644 index 0000000..c92325b --- /dev/null +++ b/app/src/main/java/com/frank/ffmpeg/mp3/Mp3LameBuilder.kt @@ -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) + } + +}