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.
- package/README.md +5 -4
- package/android/build.gradle +3 -1
- package/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt +202 -496
- package/android/src/main/java/com/reactnativecompressor/Audio/AudioExtractor.kt +112 -0
- package/android/src/main/java/com/reactnativecompressor/Audio/AudioHelper.kt +23 -0
- package/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt +5 -13
- package/android/src/main/java/com/reactnativecompressor/Utils/RealPathUtil.kt +74 -8
- package/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt +5 -0
- package/lib/commonjs/Audio/index.js +3 -42
- package/lib/commonjs/Audio/index.js.map +1 -1
- package/lib/commonjs/utils/index.js +5 -44
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/module/Audio/index.js +4 -43
- package/lib/module/Audio/index.js.map +1 -1
- package/lib/module/utils/index.js +5 -39
- package/lib/module/utils/index.js.map +1 -1
- package/lib/typescript/Audio/index.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/utils/index.d.ts +1 -6
- package/lib/typescript/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Audio/index.tsx +5 -56
- package/src/utils/index.tsx +4 -54
|
@@ -1,527 +1,233 @@
|
|
|
1
1
|
package com.reactnativecompressor.Audio
|
|
2
2
|
|
|
3
|
+
|
|
3
4
|
import android.annotation.SuppressLint
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
private
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
85
|
+
} catch (e: Exception) {
|
|
86
|
+
promise.resolve(_fileUrl)
|
|
87
|
+
}
|
|
333
88
|
}
|
|
334
89
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
if
|
|
341
|
-
|
|
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
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
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
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
216
|
+
completeCallback(e.localizedMessage, false)
|
|
217
|
+
e.printStackTrace()
|
|
488
218
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
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
|
-
|
|
522
|
-
|
|
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
|
}
|