parent
							
								
									083c306d2b
								
							
						
					
					
						commit
						d4b5956a81
					
				
									
										Binary file not shown.
									
								
							
						
									
										Binary file not shown.
									
								
							
						| @ -0,0 +1,224 @@ | ||||
| 
 | ||||
| #include "include/lame/lame.h" | ||||
| #include <jni.h> | ||||
| 
 | ||||
| lame_global_flags *glf; | ||||
| 
 | ||||
| lame_global_flags *initializeDefault(JNIEnv *env) { | ||||
|     lame_global_flags *glf = lame_init(); | ||||
|     lame_init_params(glf); | ||||
|     return glf; | ||||
| } | ||||
| 
 | ||||
| lame_global_flags *initialize( | ||||
|         JNIEnv *env, | ||||
|         jint inSamplerate, jint outChannel, | ||||
|         jint outSamplerate, jint outBitrate, jfloat scaleInput, jint mode, jint vbrMode, | ||||
|         jint quality, jint vbrQuality, jint abrMeanBitrate, jint lowpassFreq, jint highpassFreq, | ||||
|         jstring id3tagTitle, jstring id3tagArtist, jstring id3tagAlbum, | ||||
|         jstring id3tagYear, jstring id3tagComment) { | ||||
| 
 | ||||
|     lame_global_flags *glf = lame_init(); | ||||
|     lame_set_in_samplerate(glf, inSamplerate); | ||||
|     lame_set_num_channels(glf, outChannel); | ||||
|     lame_set_out_samplerate(glf, outSamplerate); | ||||
|     lame_set_brate(glf, outBitrate); | ||||
|     lame_set_quality(glf, quality); | ||||
|     lame_set_scale(glf, scaleInput); | ||||
|     lame_set_VBR_q(glf, vbrQuality); | ||||
|     lame_set_VBR_mean_bitrate_kbps(glf, abrMeanBitrate); | ||||
|     lame_set_lowpassfreq(glf, lowpassFreq); | ||||
|     lame_set_highpassfreq(glf, highpassFreq); | ||||
| 
 | ||||
|     switch (mode) { | ||||
|         case 0: | ||||
|             lame_set_mode(glf, STEREO); | ||||
|             break; | ||||
|         case 1: | ||||
|             lame_set_mode(glf, JOINT_STEREO); | ||||
|             break; | ||||
|         case 3: | ||||
|             lame_set_mode(glf, MONO); | ||||
|             break; | ||||
|         case 4: | ||||
|             lame_set_mode(glf, NOT_SET); | ||||
|             break; | ||||
|         default: | ||||
|             lame_set_mode(glf, NOT_SET); | ||||
|             break; | ||||
|     } | ||||
| 
 | ||||
|     switch (vbrMode) { | ||||
|         case 0: | ||||
|             lame_set_VBR(glf, vbr_off); | ||||
|             break; | ||||
|         case 2: | ||||
|             lame_set_VBR(glf, vbr_rh); | ||||
|             break; | ||||
|         case 3: | ||||
|             lame_set_VBR(glf, vbr_abr); | ||||
|             break; | ||||
|         case 4: | ||||
|             lame_set_VBR(glf, vbr_mtrh); | ||||
|             break; | ||||
|         case 6: | ||||
|             lame_set_VBR(glf, vbr_default); | ||||
|             break; | ||||
|         default: | ||||
|             lame_set_VBR(glf, vbr_off); | ||||
|             break; | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     const jchar *title = NULL; | ||||
|     const jchar *artist = NULL; | ||||
|     const jchar *album = NULL; | ||||
|     const jchar *year = NULL; | ||||
|     const jchar *comment = NULL; | ||||
|     if (id3tagTitle) { | ||||
|         title = (*env)->GetStringChars(env, id3tagTitle, NULL); | ||||
|     } | ||||
|     if (id3tagArtist) { | ||||
|         artist = (*env)->GetStringChars(env, id3tagArtist, NULL); | ||||
|     } | ||||
|     if (id3tagAlbum) { | ||||
|         album = (*env)->GetStringChars(env, id3tagAlbum, NULL); | ||||
|     } | ||||
|     if (id3tagYear) { | ||||
|         year = (*env)->GetStringChars(env, id3tagYear, NULL); | ||||
|     } | ||||
|     if (id3tagComment) { | ||||
|         comment = (*env)->GetStringChars(env, id3tagComment, NULL); | ||||
|     } | ||||
| 
 | ||||
|     if (title || artist || album || year || comment) { | ||||
|         id3tag_init(glf); | ||||
| 
 | ||||
|         if (title) { | ||||
|             id3tag_set_title(glf, (const char *) title); | ||||
|             (*env)->ReleaseStringChars(env, id3tagTitle, title); | ||||
|         } | ||||
|         if (artist) { | ||||
|             id3tag_set_artist(glf, (const char *) artist); | ||||
|             (*env)->ReleaseStringChars(env, id3tagArtist, artist); | ||||
|         } | ||||
|         if (album) { | ||||
|             id3tag_set_album(glf, (const char *) album); | ||||
|             (*env)->ReleaseStringChars(env, id3tagAlbum, album); | ||||
|         } | ||||
|         if (year) { | ||||
|             id3tag_set_year(glf, (const char *) year); | ||||
|             (*env)->ReleaseStringChars(env, id3tagYear, year); | ||||
|         } | ||||
|         if (comment) { | ||||
|             id3tag_set_comment(glf, (const char *) comment); | ||||
|             (*env)->ReleaseStringChars(env, id3tagComment, comment); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     lame_init_params(glf); | ||||
| 
 | ||||
| 
 | ||||
|     return glf; | ||||
| } | ||||
| 
 | ||||
| jint encode( | ||||
|         JNIEnv *env, lame_global_flags *glf, | ||||
|         jshortArray buffer_l, jshortArray buffer_r, | ||||
|         jint samples, jbyteArray mp3buf) { | ||||
|     jshort *j_buffer_l = (*env)->GetShortArrayElements(env, buffer_l, NULL); | ||||
| 
 | ||||
|     jshort *j_buffer_r = (*env)->GetShortArrayElements(env, buffer_r, NULL); | ||||
| 
 | ||||
|     const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf); | ||||
|     jbyte *j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL); | ||||
| 
 | ||||
|     int result = lame_encode_buffer(glf, j_buffer_l, j_buffer_r, | ||||
|                                     samples, j_mp3buf, mp3buf_size); | ||||
| 
 | ||||
|     (*env)->ReleaseShortArrayElements(env, buffer_l, j_buffer_l, 0); | ||||
|     (*env)->ReleaseShortArrayElements(env, buffer_r, j_buffer_r, 0); | ||||
|     (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| jint encodeBufferInterleaved( | ||||
|         JNIEnv *env, lame_global_flags *glf, | ||||
|         jshortArray pcm, jint samples, jbyteArray mp3buf) { | ||||
|     jshort *j_pcm = (*env)->GetShortArrayElements(env, pcm, NULL); | ||||
| 
 | ||||
|     const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf); | ||||
|     jbyte *j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL); | ||||
| 
 | ||||
|     int result = lame_encode_buffer_interleaved(glf, j_pcm, | ||||
|                                                 samples, j_mp3buf, mp3buf_size); | ||||
| 
 | ||||
|     (*env)->ReleaseShortArrayElements(env, pcm, j_pcm, 0); | ||||
|     (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| jint flush( | ||||
|         JNIEnv *env, lame_global_flags *glf, | ||||
|         jbyteArray mp3buf) { | ||||
|     const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf); | ||||
|     jbyte *j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL); | ||||
| 
 | ||||
|     int result = lame_encode_flush(glf, j_mp3buf, mp3buf_size); | ||||
| 
 | ||||
|     (*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| void close_lame(lame_global_flags *glf) { | ||||
|     lame_close(glf); | ||||
|     glf = NULL; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| JNIEXPORT void JNICALL Java_com_frank_ffmpeg_AudioPlayer_lameInitDefault | ||||
|         (JNIEnv *env, jclass jclazz) { | ||||
| 
 | ||||
|     glf = initializeDefault(env); | ||||
| } | ||||
| 
 | ||||
| JNIEXPORT void JNICALL Java_com_frank_ffmpeg_AudioPlayer_lameInit( | ||||
|         JNIEnv *env, jclass cls, jint inSampleRate, jint outChannel, | ||||
|         jint outSampleRate, jint outBitrate, jfloat scaleInput, jint mode, jint vbrMode, | ||||
|         jint quality, jint vbrQuality, jint abrMeanBitrate, jint lowPassFreq, jint highPassFreq, | ||||
|         jstring id3tagTitle, jstring id3tagArtist, jstring id3tagAlbum, | ||||
|         jstring id3tagYear, jstring id3tagComment) { | ||||
| 
 | ||||
|     glf = initialize(env, inSampleRate, outChannel, outSampleRate, outBitrate, scaleInput, mode, | ||||
|                      vbrMode, | ||||
|                      quality, vbrQuality, abrMeanBitrate, lowPassFreq, highPassFreq, id3tagTitle, | ||||
|                      id3tagArtist, id3tagAlbum, | ||||
|                      id3tagYear, | ||||
|                      id3tagComment); | ||||
| } | ||||
| 
 | ||||
| JNIEXPORT jint JNICALL Java_com_frank_ffmpeg_AudioPlayer_lameEncode( | ||||
|         JNIEnv *env, jclass cls, jshortArray buffer_l, | ||||
|         jshortArray buffer_r, jint samples, jbyteArray mp3buf) { | ||||
|     return encode(env, glf, buffer_l, buffer_r, samples, mp3buf); | ||||
| } | ||||
| 
 | ||||
| JNIEXPORT jint JNICALL Java_com_frank_ffmpeg_AudioPlayer_encodeBufferInterleaved( | ||||
|         JNIEnv *env, jclass cls, jshortArray pcm, | ||||
|         jint samples, jbyteArray mp3buf) { | ||||
|     return encodeBufferInterleaved(env, glf, pcm, samples, mp3buf); | ||||
| } | ||||
| 
 | ||||
| JNIEXPORT jint JNICALL Java_com_frank_ffmpeg_AudioPlayer_lameFlush( | ||||
|         JNIEnv *env, jclass cls, jbyteArray mp3buf) { | ||||
|     return flush(env, glf, mp3buf); | ||||
| } | ||||
| 
 | ||||
| JNIEXPORT void JNICALL Java_com_frank_ffmpeg_AudioPlayer_lameClose( | ||||
|         JNIEnv *env, jclass cls) { | ||||
|     close_lame(glf); | ||||
| } | ||||
									
										
											File diff suppressed because it is too large
											Load Diff
										
									
								
							
						| @ -0,0 +1,340 @@ | ||||
| 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,71 @@ | ||||
| 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,147 @@ | ||||
| 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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue