react-native-compressor 1.8.5 → 1.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,527 +1,233 @@
1
1
  package com.reactnativecompressor.Audio
2
2
 
3
+
3
4
  import android.annotation.SuppressLint
4
- import android.media.MediaCodec
5
- import android.media.MediaCodecInfo
6
- import android.media.MediaCodecList
7
- import android.media.MediaExtractor
8
- import android.media.MediaFormat
9
- import android.media.MediaMetadataRetriever
10
- import android.media.MediaMuxer
11
- import android.os.Build
12
- import android.util.Log
13
- import androidx.annotation.RequiresApi
14
- import com.reactnativecompressor.Video.VideoCompressor.video.OutputSurface
5
+ import com.facebook.react.bridge.Promise
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.naman14.androidlame.LameBuilder
8
+ import com.naman14.androidlame.WaveReader
9
+ import com.reactnativecompressor.Utils.MediaCache
10
+ import com.reactnativecompressor.Utils.Utils
11
+ import com.reactnativecompressor.Utils.Utils.addLog
12
+ import javazoom.jl.converter.Converter
13
+ import javazoom.jl.decoder.JavaLayerException
14
+ import java.io.BufferedOutputStream
15
15
  import java.io.File
16
+ import java.io.FileNotFoundException
17
+ import java.io.FileOutputStream
16
18
  import java.io.IOException
17
- import java.nio.ByteBuffer
18
19
 
19
20
  class AudioCompressor {
20
- var path: String? = null
21
- private var outputPath: String? = null
22
- private var mBufferInfo: MediaCodec.BufferInfo? = null
23
- private var mMuxer: MediaMuxer? = null
24
- private var mEncoder: MediaCodec? = null
25
- private var mDecoder: MediaCodec? = null
26
- private var mTrackIndex = 0
27
- private var mInputSurface: OutputSurface? = null
28
-
29
- // bit rate, in bits per second
30
- private var mBitRate = -1
31
- private val TIMEOUT_USEC = 2500
32
-
33
- /***
34
- * trans video and audio by mediacodec
35
- *
36
- */
37
- @SuppressLint("LongLogTag")
38
- @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
39
- fun CompressAudio(sourcePath: String?, destinationPath: String?, nbitrate: Int): Boolean {
40
- path = sourcePath
41
- outputPath = destinationPath
42
- if (checkParmsError(sourcePath, destinationPath, nbitrate)) {
43
- return false
21
+ companion object {
22
+ val TAG="AudioMain"
23
+ private const val OUTPUT_STREAM_BUFFER = 8192
24
+
25
+ var outputStream: BufferedOutputStream? = null
26
+ var waveReader: WaveReader? = null
27
+ @JvmStatic
28
+ fun CompressAudio(
29
+ fileUrl: String,
30
+ quality: String,
31
+ context: ReactApplicationContext,
32
+ promise: Promise,
33
+ ) {
34
+ var _fileUrl=fileUrl
35
+ try {
36
+ val filePath = fileUrl.replace("file://", "")
37
+ var wavPath=filePath;
38
+ var isNonWav:Boolean=false
39
+ if (fileUrl.endsWith(".mp4", ignoreCase = true))
40
+ {
41
+ addLog("mp4 file found")
42
+ val mp3Path= Utils.generateCacheFilePath("mp3", context)
43
+ AudioExtractor().genVideoUsingMuxer(fileUrl, mp3Path, -1, -1, true, false)
44
+ _fileUrl="file:/"+mp3Path
45
+ wavPath= Utils.generateCacheFilePath("wav", context)
46
+ try {
47
+ val converter = Converter()
48
+ converter.convert(mp3Path, wavPath)
49
+ } catch (e: JavaLayerException) {
50
+ addLog("JavaLayerException error"+e.localizedMessage)
51
+ e.printStackTrace();
52
+ }
53
+ isNonWav=true
44
54
  }
45
-
46
- //get origin video info
47
- val retriever = MediaMetadataRetriever()
48
- retriever.setDataSource(path)
49
- // String framecount = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT);
50
- val duration = java.lang.Long.valueOf(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)) * 1000
51
- val startTime: Long = -1
52
- val endTime: Long = -1
53
- mBitRate = nbitrate
54
- // NUM_FRAMES = Integer.getInteger(framecount);
55
- //IFRAME_INTERVAL = Integer.valueOf(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
56
- var error = false
57
- val videoStartTime: Long = -1
58
- val time = System.currentTimeMillis()
59
- val cacheFile = File(destinationPath)
60
- val inputFile = File(path)
61
- if (!inputFile.canRead()) {
62
- return false
55
+ else if (!fileUrl.endsWith(".wav", ignoreCase = true))
56
+ {
57
+ addLog("non wav file found")
58
+ wavPath= Utils.generateCacheFilePath("wav", context)
59
+ try {
60
+ val converter = Converter()
61
+ converter.convert(filePath, wavPath)
62
+ } catch (e: JavaLayerException) {
63
+ addLog("JavaLayerException error"+e.localizedMessage)
64
+ e.printStackTrace();
63
65
  }
64
- var extractor: MediaExtractor? = null
65
- var mAudioExtractor: MediaExtractor? = null
66
- try {
67
- // video MediaExtractor
68
- extractor = MediaExtractor()
69
- extractor.setDataSource(inputFile.toString())
70
-
71
- // audio MediaExtractor
72
- mAudioExtractor = MediaExtractor()
73
- mAudioExtractor.setDataSource(inputFile.toString())
74
- mMuxer = try {
75
- MediaMuxer(outputPath!!, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
76
- } catch (ioe: IOException) {
77
- throw RuntimeException("MediaMuxer creation failed", ioe)
78
- }
79
- val muxerAudioTrackIndex = 0
80
- val audioIndex = selectTrack(mAudioExtractor, true)
81
- if (audioIndex >= 0) {
82
- mAudioExtractor.selectTrack(audioIndex)
83
- mAudioExtractor.seekTo(0, MediaExtractor.SEEK_TO_PREVIOUS_SYNC)
84
- val trackFormat = mAudioExtractor.getTrackFormat(audioIndex)
85
- // muxerAudioTrackIndex = mMuxer.addTrack(trackFormat);
86
-
87
- // extractor.unselectTrack(muxerAudioTrackIndex);
88
- }
89
- /**
90
- * mediacodec + surface + opengl
91
- */
92
- Log.d("CompressAudio", "CompressAudio: ")
93
- val videoIndex = selectTrack(extractor, true)
94
- if (videoIndex >= 0) {
95
- var videoTime: Long = -1
96
- var outputDone = false
97
- var inputDone = false
98
- var decoderDone = false
99
- val swapUV = 0
100
- var videoTrackIndex = MEDIATYPE_NOT_AUDIO_VIDEO
101
- extractor.selectTrack(videoIndex)
102
- if (startTime > 0) {
103
- extractor.seekTo(startTime, MediaExtractor.SEEK_TO_PREVIOUS_SYNC)
104
- } else {
105
- extractor.seekTo(0, MediaExtractor.SEEK_TO_PREVIOUS_SYNC)
106
- }
107
- val inputFormat = extractor.getTrackFormat(videoIndex)
108
- /**
109
- * init mediacodec / encoder and decoder
110
- */
111
- prepareEncoder(inputFormat)
112
- var decoderInputBuffers: Array<ByteBuffer?>? = null
113
- var encoderOutputBuffers: Array<ByteBuffer?>? = null
114
- decoderInputBuffers = mDecoder!!.inputBuffers
115
- encoderOutputBuffers = mEncoder!!.outputBuffers
116
- while (!outputDone) {
117
- if (!inputDone) {
118
- var eof = false
119
- val index = extractor.sampleTrackIndex
120
- if (index == videoIndex) {
121
- val inputBufIndex = mDecoder!!.dequeueInputBuffer(TIMEOUT_USEC.toLong())
122
- if (inputBufIndex >= 0) {
123
- var inputBuf: ByteBuffer?
124
- inputBuf = if (Build.VERSION.SDK_INT < 21) {
125
- decoderInputBuffers[inputBufIndex]
126
- } else {
127
- mDecoder!!.getInputBuffer(inputBufIndex)
128
- }
129
- val chunkSize = extractor.readSampleData(inputBuf!!, 0)
130
- if (chunkSize < 0) {
131
- mDecoder!!.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
132
- inputDone = true
133
- } else {
134
- mDecoder!!.queueInputBuffer(inputBufIndex, 0, chunkSize, extractor.sampleTime, 0)
135
- extractor.advance()
136
- }
137
- }
138
- } else if (index == -1) {
139
- eof = true
140
- }
141
- if (eof) {
142
- val inputBufIndex = mDecoder!!.dequeueInputBuffer(TIMEOUT_USEC.toLong())
143
- if (inputBufIndex >= 0) {
144
- mDecoder!!.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
145
- inputDone = true
146
- }
147
- }
148
- }
149
- var decoderOutputAvailable = !decoderDone
150
- var encoderOutputAvailable = true
151
- while (decoderOutputAvailable || encoderOutputAvailable) {
152
- val encoderStatus = mEncoder!!.dequeueOutputBuffer(mBufferInfo!!, TIMEOUT_USEC.toLong())
153
- if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
154
- encoderOutputAvailable = false
155
- } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
156
- if (Build.VERSION.SDK_INT < 21) {
157
- encoderOutputBuffers = mEncoder!!.outputBuffers
158
- }
159
- } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
160
- val newFormat = mEncoder!!.outputFormat
161
- if (videoTrackIndex == MEDIATYPE_NOT_AUDIO_VIDEO) {
162
- videoTrackIndex = mMuxer!!.addTrack(newFormat)
163
- mTrackIndex = videoTrackIndex
164
- mMuxer!!.start()
165
- }
166
- } else if (encoderStatus < 0) {
167
- throw RuntimeException("unexpected result from mEncoder.dequeueOutputBuffer: $encoderStatus")
168
- } else {
169
- var encodedData: ByteBuffer?
170
- encodedData = if (Build.VERSION.SDK_INT < 21) {
171
- encoderOutputBuffers!![encoderStatus]
172
- } else {
173
- mEncoder!!.getOutputBuffer(encoderStatus)
174
- }
175
- if (encodedData == null) {
176
- throw RuntimeException("encoderOutputBuffer $encoderStatus was null")
177
- }
178
- if (mBufferInfo!!.size > 1) {
179
- if (mBufferInfo!!.flags and MediaCodec.BUFFER_FLAG_CODEC_CONFIG == 0) {
180
- mMuxer!!.writeSampleData(videoTrackIndex, encodedData, mBufferInfo!!)
181
- } else if (videoTrackIndex == MEDIATYPE_NOT_AUDIO_VIDEO) {
182
- val csd = ByteArray(mBufferInfo!!.size)
183
- encodedData.limit(mBufferInfo!!.offset + mBufferInfo!!.size)
184
- encodedData.position(mBufferInfo!!.offset)
185
- encodedData[csd]
186
- var sps: ByteBuffer? = null
187
- var pps: ByteBuffer? = null
188
- for (a in mBufferInfo!!.size - 1 downTo 0) {
189
- if (a > 3) {
190
- if (csd[a].toInt() == 1 && csd[a - 1].toInt() == 0 && csd[a - 2].toInt() == 0 && csd[a - 3].toInt() == 0) {
191
- sps = ByteBuffer.allocate(a - 3)
192
- pps = ByteBuffer.allocate(mBufferInfo!!.size - (a - 3))
193
- sps.put(csd, 0, a - 3).position(0)
194
- pps.put(csd, a - 3, mBufferInfo!!.size - (a - 3)).position(0)
195
- break
196
- }
197
- } else {
198
- break
199
- }
200
- }
201
- val newFormat = MediaFormat.createAudioFormat(MIME_TYPE, nbitrate, 1)
202
- if (sps != null && pps != null) {
203
- newFormat.setByteBuffer("csd-0", sps)
204
- newFormat.setByteBuffer("csd-1", pps)
205
- }
206
- videoTrackIndex = mMuxer!!.addTrack(newFormat)
207
- mMuxer!!.start()
208
- }
209
- }
210
- outputDone = mBufferInfo!!.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM != 0
211
- mEncoder!!.releaseOutputBuffer(encoderStatus, false)
212
- }
213
- if (encoderStatus != MediaCodec.INFO_TRY_AGAIN_LATER) {
214
- continue
215
- }
216
- if (!decoderDone) {
217
- val decoderStatus = mDecoder!!.dequeueOutputBuffer(mBufferInfo!!, TIMEOUT_USEC.toLong())
218
- if (decoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
219
- decoderOutputAvailable = false
220
- } else if (decoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
221
- } else if (decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
222
- val newFormat = mDecoder!!.outputFormat
223
- Log.e(TAG, "newFormat = $newFormat")
224
- } else if (decoderStatus < 0) {
225
- throw RuntimeException("unexpected result from mDecoder.dequeueOutputBuffer: $decoderStatus")
226
- } else {
227
- var doRender = false
228
- doRender = mBufferInfo!!.size != 0
229
- if (endTime > 0 && mBufferInfo!!.presentationTimeUs >= endTime) {
230
- inputDone = true
231
- decoderDone = true
232
- doRender = false
233
- mBufferInfo!!.flags = mBufferInfo!!.flags or MediaCodec.BUFFER_FLAG_END_OF_STREAM
234
- }
235
- if (startTime > 0 && videoTime == -1L) {
236
- if (mBufferInfo!!.presentationTimeUs < startTime) {
237
- doRender = false
238
- Log.e(TAG, "drop frame startTime = " + startTime + " present time = " + mBufferInfo!!.presentationTimeUs)
239
- } else {
240
- videoTime = mBufferInfo!!.presentationTimeUs
241
- }
242
- }
243
- mDecoder!!.releaseOutputBuffer(decoderStatus, doRender)
244
- if (mBufferInfo!!.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM != 0) {
245
- decoderOutputAvailable = false
246
- outputDone = true
247
- Log.e(TAG, "decoder stream end")
248
- }
249
- }
250
- }
251
- }
252
- }
253
- }
254
- extractor.unselectTrack(videoIndex)
255
- writeAudioTrack(mAudioExtractor, mMuxer!!, mBufferInfo, cacheFile, muxerAudioTrackIndex)
256
- } catch (e: Exception) {
257
- error = true
258
- Log.e(TAG, e.message!!)
259
- } finally {
260
- if (extractor != null) {
261
- extractor.release()
262
- extractor = null
263
- }
264
- if (mAudioExtractor != null) {
265
- mAudioExtractor.release()
266
- mAudioExtractor = null
267
- }
268
- Log.e(TAG, "time = " + (System.currentTimeMillis() - time))
66
+ isNonWav=true
269
67
  }
270
- Log.e(TAG + " Path", path + "")
271
- Log.e(TAG + " Path", cacheFile.path + "")
272
- Log.e(TAG + " Path", inputFile.path + "")
273
- releaseCoder()
274
- return if (error) false else true
275
- }
276
68
 
277
- private fun checkParmsError(sourcePath: String?, destinationPath: String?, nbitrate: Int): Boolean {
278
- return if (nbitrate <= 0) true else false
279
- }
280
69
 
281
- @SuppressLint("WrongConstant")
282
- @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
283
- @Throws(Exception::class)
284
- private fun simpleReadAndWriteTrack(extractor: MediaExtractor, mediaMuxer: MediaMuxer, info: MediaCodec.BufferInfo, start: Long, end: Long, file: File, isAudio: Boolean): Long {
285
- val trackIndex = selectTrack(extractor, isAudio)
286
- if (trackIndex >= 0) {
287
- extractor.selectTrack(trackIndex)
288
- val trackFormat = extractor.getTrackFormat(trackIndex)
289
- val muxerTrackIndex = mediaMuxer.addTrack(trackFormat)
290
- if (!isAudio) mediaMuxer.start()
291
- val maxBufferSize = trackFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)
292
- var inputDone = false
293
- if (start > 0) {
294
- extractor.seekTo(start, MediaExtractor.SEEK_TO_PREVIOUS_SYNC)
295
- } else {
296
- extractor.seekTo(0, MediaExtractor.SEEK_TO_PREVIOUS_SYNC)
70
+ autoCompressHelper(wavPath, quality,context) { mp3Path, finished ->
71
+ if (finished) {
72
+ val returnableFilePath:String="file://$mp3Path"
73
+ addLog("finished: " + returnableFilePath)
74
+ MediaCache.removeCompletedImagePath(fileUrl)
75
+ if(isNonWav)
76
+ {
77
+ File(wavPath).delete()
297
78
  }
298
- val buffer = ByteBuffer.allocateDirect(maxBufferSize)
299
- var startTime: Long = -1
300
- while (!inputDone) {
301
- var eof = false
302
- val index = extractor.sampleTrackIndex
303
- if (index == trackIndex) {
304
- info.size = extractor.readSampleData(buffer, 0)
305
- if (info.size < 0) {
306
- info.size = 0
307
- eof = true
308
- } else {
309
- info.presentationTimeUs = extractor.sampleTime
310
- if (start > 0 && startTime == -1L) {
311
- startTime = info.presentationTimeUs
312
- }
313
- if (end < 0 || info.presentationTimeUs < end) {
314
- info.offset = 0
315
- info.flags = extractor.sampleFlags
316
- mediaMuxer.writeSampleData(muxerTrackIndex, buffer, info)
317
- extractor.advance()
318
- } else {
319
- eof = true
320
- }
321
- }
322
- } else if (index == -1) {
323
- eof = true
324
- }
325
- if (eof) {
326
- inputDone = true
327
- }
328
- }
329
- extractor.unselectTrack(trackIndex)
330
- return startTime
79
+ promise.resolve(returnableFilePath)
80
+ } else {
81
+ addLog("error: "+mp3Path)
82
+ promise.resolve(_fileUrl)
83
+ }
331
84
  }
332
- return -1
85
+ } catch (e: Exception) {
86
+ promise.resolve(_fileUrl)
87
+ }
333
88
  }
334
89
 
335
- @SuppressLint("WrongConstant")
336
- @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
337
- @Throws(Exception::class)
338
- private fun writeAudioTrack(extractor: MediaExtractor, mediaMuxer: MediaMuxer, info: MediaCodec.BufferInfo?, file: File, muxerTrackIndex: Int): Long {
339
- val trackIndex = selectTrack(extractor, true)
340
- if (trackIndex >= 0) {
341
- val trackFormat = extractor.getTrackFormat(trackIndex)
342
- val maxBufferSize = info!!.size
343
- val byteBuffer = ByteBuffer.allocate(maxBufferSize)
344
- var audioPresentationTimeUs: Long = 0
345
- val audioBufferInfo = MediaCodec.BufferInfo()
346
- extractor.selectTrack(mTrackIndex)
347
- /*
348
- * the last audio presentation time.
349
- */
350
- var lastEndAudioTimeUs: Long = 0
351
- while (true) {
352
- val readAudioSampleSize = extractor.readSampleData(byteBuffer, 0)
353
- if (readAudioSampleSize < 0) {
354
- //if end of the stream, unselect
355
- extractor.unselectTrack(mTrackIndex)
356
- if (audioPresentationTimeUs >= 0) {
357
- //if has reach the end of the video time ,just exit
358
- break
359
- } else {
360
- //if not the end of the video time, just repeat.
361
- lastEndAudioTimeUs += audioPresentationTimeUs
362
- extractor.selectTrack(trackIndex)
363
- continue
364
- }
365
- }
366
- val audioSampleTime = extractor.sampleTime
367
- audioBufferInfo.size = readAudioSampleSize
368
- audioBufferInfo.presentationTimeUs = audioSampleTime + lastEndAudioTimeUs
369
- if (audioBufferInfo.presentationTimeUs > 0) {
370
- extractor.unselectTrack(trackIndex)
371
- break
372
- }
373
- audioPresentationTimeUs = 0
374
- audioBufferInfo.offset = 0
375
- audioBufferInfo.flags = extractor.sampleFlags
376
- mediaMuxer.writeSampleData(trackIndex, byteBuffer, audioBufferInfo)
377
- extractor.advance()
378
- }
379
- //
380
-
381
-
382
- // boolean inputDone = false;
383
- // if (start > 0) {
384
- // extractor.seekTo(start, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
385
- // } else {
386
- // extractor.seekTo(0, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
387
- // }
388
- // ByteBuffer buffer = ByteBuffer.allocateDirect(maxBufferSize);
389
- // long startTime = -1;
390
- //
391
- // while (!inputDone) {
392
- //
393
- // boolean eof = false;
394
- // int index = extractor.getSampleTrackIndex();
395
- // if (index == trackIndex) {
396
- // info.size = extractor.readSampleData(buffer, 0);
397
- //
398
- // if (info.size < 0) {
399
- // info.size = 0;
400
- // eof = true;
401
- // } else {
402
- // info.presentationTimeUs = extractor.getSampleTime();
403
- // if (start > 0 && startTime == -1) {
404
- // startTime = info.presentationTimeUs;
405
- // }
406
- // if (end < 0 || info.presentationTimeUs < end) {
407
- // info.offset = 0;
408
- // info.flags = extractor.getSampleFlags();
409
- // mediaMuxer.writeSampleData(muxerTrackIndex, buffer, info);
410
- // extractor.advance();
411
- // } else {
412
- // eof = true;
413
- // }
414
- // }
415
- // } else if (index == -1) {
416
- // eof = true;
417
- // }
418
- // if (eof) {
419
- // inputDone = true;
420
- // }
421
- // }
422
- //
423
- // extractor.unselectTrack(trackIndex);
424
- // return startTime;
425
- }
426
- return -1
90
+ private fun getAudioBitrateByQuality(quality: String): Int {
91
+ return when (quality) {
92
+ "low" -> 64 // Set your low bitrate value here
93
+ "medium" -> 128 // Set your medium bitrate value here
94
+ "high" -> 256 // Set your high bitrate value here
95
+ else -> 128 // Default to medium bitrate if quality is not recognized
96
+ }
427
97
  }
428
98
 
429
- private fun selectTrack(extractor: MediaExtractor, audio: Boolean): Int {
430
- val numTracks = extractor.trackCount
431
- for (i in 0 until numTracks) {
432
- val format = extractor.getTrackFormat(i)
433
- val mime = format.getString(MediaFormat.KEY_MIME)
434
- if (audio) {
435
- if (mime!!.startsWith("audio/")) {
436
- return i
437
- }
438
- } else {
439
- if (mime!!.startsWith("video/")) {
440
- return i
99
+ @SuppressLint("WrongConstant")
100
+ private fun autoCompressHelper(
101
+ fileUrl: String,
102
+ quality: String,
103
+ context: ReactApplicationContext,
104
+ completeCallback: (String, Boolean) -> Unit
105
+ ) {
106
+ var isCompletedCallbackTriggered:Boolean=false
107
+ try {
108
+ var mp3Path = Utils.generateCacheFilePath("mp3", context)
109
+ val input = File(fileUrl)
110
+ val output = File(mp3Path)
111
+ val audioBitrate= getAudioBitrateByQuality(quality)
112
+
113
+ val CHUNK_SIZE = 8192
114
+ addLog("Initialising wav reader")
115
+
116
+ waveReader = WaveReader(input)
117
+
118
+ try {
119
+ waveReader!!.openWave()
120
+ } catch (e: IOException) {
121
+ e.printStackTrace()
122
+ }
123
+
124
+ addLog("Intitialising encoder")
125
+ val androidLame = LameBuilder()
126
+ .setInSampleRate(waveReader!!.sampleRate)
127
+ .setOutChannels(waveReader!!.channels)
128
+ .setOutBitrate(audioBitrate)
129
+ .setOutSampleRate(waveReader!!.sampleRate)
130
+ .build()
131
+
132
+ try {
133
+ outputStream = BufferedOutputStream(FileOutputStream(output), OUTPUT_STREAM_BUFFER)
134
+ } catch (e: FileNotFoundException) {
135
+ e.printStackTrace()
136
+ }
137
+
138
+ var bytesRead = 0
139
+
140
+ val buffer_l = ShortArray(CHUNK_SIZE)
141
+ val buffer_r = ShortArray(CHUNK_SIZE)
142
+ val mp3Buf = ByteArray(CHUNK_SIZE)
143
+
144
+ val channels = waveReader!!.channels
145
+
146
+ addLog("started encoding")
147
+ while (true) {
148
+ try {
149
+ if (channels == 2) {
150
+
151
+ bytesRead = waveReader!!.read(buffer_l, buffer_r, CHUNK_SIZE)
152
+ addLog("bytes read=$bytesRead")
153
+
154
+ if (bytesRead > 0) {
155
+
156
+ var bytesEncoded = 0
157
+ bytesEncoded = androidLame.encode(buffer_l, buffer_r, bytesRead, mp3Buf)
158
+ addLog("bytes encoded=$bytesEncoded")
159
+
160
+ if (bytesEncoded > 0) {
161
+ try {
162
+ addLog("writing mp3 buffer to outputstream with $bytesEncoded bytes")
163
+ outputStream!!.write(mp3Buf, 0, bytesEncoded)
164
+ } catch (e: IOException) {
165
+ e.printStackTrace()
441
166
  }
442
- }
443
- }
444
- return MEDIATYPE_NOT_AUDIO_VIDEO
445
- }
446
167
 
447
- private fun selectEncoder(mime: String): String? {
448
- for (index in 0 until MediaCodecList.getCodecCount()) {
449
- val codecInfo = MediaCodecList.getCodecInfoAt(index)
450
- if (!codecInfo.isEncoder) {
451
- continue
452
- }
453
- for (type in codecInfo.supportedTypes) {
454
- if (type.equals(mime, ignoreCase = true)) {
455
- return MIME_TYPE
168
+ }
169
+
170
+ } else
171
+ break
172
+ } else {
173
+
174
+ bytesRead = waveReader!!.read(buffer_l, CHUNK_SIZE)
175
+ addLog("bytes read=$bytesRead")
176
+
177
+ if (bytesRead > 0) {
178
+ var bytesEncoded = 0
179
+
180
+ bytesEncoded = androidLame.encode(buffer_l, buffer_l, bytesRead, mp3Buf)
181
+ addLog("bytes encoded=$bytesEncoded")
182
+
183
+ if (bytesEncoded > 0) {
184
+ try {
185
+ addLog("writing mp3 buffer to outputstream with $bytesEncoded bytes")
186
+ outputStream!!.write(mp3Buf, 0, bytesEncoded)
187
+ } catch (e: IOException) {
188
+ e.printStackTrace()
456
189
  }
457
- }
458
- }
459
- return null
460
- }
461
190
 
462
- /**
463
- * Configures encoder and muxer state, and prepares the input Surface.
464
- */
465
- @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
466
- private fun prepareEncoder(format: MediaFormat) {
467
- mBufferInfo = MediaCodec.BufferInfo()
468
- val mAudioFormat = MediaFormat.createAudioFormat(MIME_TYPE, mBitRate, 1)
469
- if (VERBOSE) Log.d(TAG, "format: $mAudioFormat")
470
- mAudioFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, format.getInteger(MediaFormat.KEY_SAMPLE_RATE))
471
- mAudioFormat.setInteger(MediaFormat.KEY_BIT_RATE, format.getInteger(MediaFormat.KEY_BIT_RATE))
472
- mAudioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, format.getInteger(MediaFormat.KEY_CHANNEL_COUNT))
473
- mAudioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC)
474
- mAudioFormat.setString(MediaFormat.KEY_MIME, MIME_TYPE)
475
- mAudioFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 10 * 1024)
476
- try {
477
- mEncoder = MediaCodec.createEncoderByType(MIME_TYPE)
478
- mEncoder!!.configure(mAudioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
479
- mEncoder!!.start()
480
- Log.d(TAG, "prepareEncoder...")
191
+ }
192
+
193
+ } else
194
+ break
195
+ }
196
+
197
+
481
198
  } catch (e: IOException) {
482
- e.printStackTrace()
199
+ e.printStackTrace()
483
200
  }
201
+
202
+ }
203
+
204
+ addLog("flushing final mp3buffer")
205
+ val outputMp3buf = androidLame.flush(mp3Buf)
206
+ addLog("flushed $outputMp3buf bytes")
207
+ if (outputMp3buf > 0) {
484
208
  try {
485
- mDecoder = MediaCodec.createDecoderByType(format.getString(MediaFormat.KEY_MIME)!!)
209
+ addLog("writing final mp3buffer to outputstream")
210
+ outputStream!!.write(mp3Buf, 0, outputMp3buf)
211
+ addLog("closing output stream")
212
+ outputStream!!.close()
213
+ completeCallback(output.absolutePath, true)
214
+ isCompletedCallbackTriggered=true
486
215
  } catch (e: IOException) {
487
- e.printStackTrace()
216
+ completeCallback(e.localizedMessage, false)
217
+ e.printStackTrace()
488
218
  }
489
- mDecoder!!.configure(format, null, null, 0)
490
- mDecoder!!.start()
491
- // mTrackIndex = -1;
219
+ }
220
+
221
+ } catch (e: IOException) {
222
+ completeCallback(e.localizedMessage, false)
223
+ }
224
+ if(!isCompletedCallbackTriggered)
225
+ {
226
+ completeCallback("something went wrong", false)
227
+ }
492
228
  }
493
229
 
494
- /**
495
- * Releases encoder resources. May be called after partial / failed initialization.
496
- */
497
- @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
498
- private fun releaseCoder() {
499
- if (VERBOSE) Log.d(TAG, "releasing encoder objects")
500
- if (mEncoder != null) {
501
- mEncoder!!.stop()
502
- mEncoder!!.release()
503
- mEncoder = null
504
- }
505
- if (mDecoder != null) {
506
- mDecoder!!.stop()
507
- mDecoder!!.release()
508
- mDecoder = null
509
- }
510
- if (mInputSurface != null) {
511
- mInputSurface!!.release()
512
- mInputSurface = null
513
- }
514
- if (mMuxer != null) {
515
- mMuxer!!.stop()
516
- mMuxer!!.release()
517
- mMuxer = null
518
- }
519
- }
520
230
 
521
- companion object {
522
- private const val TAG = "AudioCompressor"
523
- private const val VERBOSE = true // lots of logging
524
- const val MIME_TYPE = MediaFormat.MIMETYPE_AUDIO_AAC
525
- private const val MEDIATYPE_NOT_AUDIO_VIDEO = -233
526
- }
231
+
232
+ }
527
233
  }