react-native-compressor 1.8.5 → 1.8.6
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 +3 -3
- package/android/build.gradle +3 -0
- package/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt +174 -496
- 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,205 @@
|
|
|
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 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 java.io.BufferedOutputStream
|
|
15
14
|
import java.io.File
|
|
15
|
+
import java.io.FileNotFoundException
|
|
16
|
+
import java.io.FileOutputStream
|
|
16
17
|
import java.io.IOException
|
|
17
|
-
import java.nio.ByteBuffer
|
|
18
18
|
|
|
19
19
|
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
|
-
|
|
20
|
+
companion object {
|
|
21
|
+
val TAG="AudioMain"
|
|
22
|
+
private const val OUTPUT_STREAM_BUFFER = 8192
|
|
23
|
+
|
|
24
|
+
var outputStream: BufferedOutputStream? = null
|
|
25
|
+
var waveReader: WaveReader? = null
|
|
26
|
+
@JvmStatic
|
|
27
|
+
fun CompressAudio(
|
|
28
|
+
fileUrl: String,
|
|
29
|
+
quality: String,
|
|
30
|
+
context: ReactApplicationContext,
|
|
31
|
+
promise: Promise,
|
|
32
|
+
) {
|
|
33
|
+
try {
|
|
34
|
+
val filePath = fileUrl.replace("file://", "")
|
|
35
|
+
var wavPath=filePath;
|
|
36
|
+
var isNonWav:Boolean=false
|
|
37
|
+
if (!fileUrl.endsWith(".waw", ignoreCase = true))
|
|
38
|
+
{
|
|
39
|
+
addLog("mp3 file found")
|
|
40
|
+
wavPath= Utils.generateCacheFilePath("wav", context)
|
|
41
|
+
val converter = Converter()
|
|
42
|
+
converter.convert(filePath, wavPath)
|
|
43
|
+
isNonWav=true
|
|
44
44
|
}
|
|
45
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
|
|
63
|
-
}
|
|
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
|
|
46
|
+
|
|
47
|
+
autoCompressHelper(wavPath, quality,context) { mp3Path, finished ->
|
|
48
|
+
if (finished) {
|
|
49
|
+
val returnableFilePath:String="file://$mp3Path"
|
|
50
|
+
addLog("finished: " + returnableFilePath)
|
|
51
|
+
MediaCache.removeCompletedImagePath(fileUrl)
|
|
52
|
+
if(isNonWav)
|
|
53
|
+
{
|
|
54
|
+
File(wavPath).delete()
|
|
267
55
|
}
|
|
268
|
-
|
|
56
|
+
promise.resolve(returnableFilePath)
|
|
57
|
+
} else {
|
|
58
|
+
addLog("error: "+mp3Path)
|
|
59
|
+
promise.resolve(fileUrl)
|
|
60
|
+
}
|
|
269
61
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
releaseCoder()
|
|
274
|
-
return if (error) false else true
|
|
62
|
+
} catch (e: Exception) {
|
|
63
|
+
promise.resolve(fileUrl)
|
|
64
|
+
}
|
|
275
65
|
}
|
|
276
66
|
|
|
277
|
-
private fun
|
|
278
|
-
|
|
67
|
+
private fun getAudioBitrateByQuality(quality: String): Int {
|
|
68
|
+
return when (quality) {
|
|
69
|
+
"low" -> 64 // Set your low bitrate value here
|
|
70
|
+
"medium" -> 128 // Set your medium bitrate value here
|
|
71
|
+
"high" -> 256 // Set your high bitrate value here
|
|
72
|
+
else -> 128 // Default to medium bitrate if quality is not recognized
|
|
73
|
+
}
|
|
279
74
|
}
|
|
280
75
|
|
|
281
76
|
@SuppressLint("WrongConstant")
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
return -1
|
|
333
|
-
}
|
|
77
|
+
private fun autoCompressHelper(
|
|
78
|
+
fileUrl: String,
|
|
79
|
+
quality: String,
|
|
80
|
+
context: ReactApplicationContext,
|
|
81
|
+
completeCallback: (String, Boolean) -> Unit
|
|
82
|
+
) {
|
|
83
|
+
try {
|
|
84
|
+
var mp3Path = Utils.generateCacheFilePath("mp3", context)
|
|
85
|
+
val input = File(fileUrl)
|
|
86
|
+
val output = File(mp3Path)
|
|
87
|
+
val audioBitrate= getAudioBitrateByQuality(quality)
|
|
88
|
+
|
|
89
|
+
val CHUNK_SIZE = 8192
|
|
90
|
+
addLog("Initialising wav reader")
|
|
91
|
+
|
|
92
|
+
waveReader = WaveReader(input)
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
waveReader!!.openWave()
|
|
96
|
+
} catch (e: IOException) {
|
|
97
|
+
e.printStackTrace()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
addLog("Intitialising encoder")
|
|
101
|
+
val androidLame = LameBuilder()
|
|
102
|
+
.setInSampleRate(waveReader!!.sampleRate)
|
|
103
|
+
.setOutChannels(waveReader!!.channels)
|
|
104
|
+
.setOutBitrate(audioBitrate)
|
|
105
|
+
.setOutSampleRate(waveReader!!.sampleRate)
|
|
106
|
+
.build()
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
outputStream = BufferedOutputStream(FileOutputStream(output), OUTPUT_STREAM_BUFFER)
|
|
110
|
+
} catch (e: FileNotFoundException) {
|
|
111
|
+
e.printStackTrace()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
var bytesRead = 0
|
|
115
|
+
|
|
116
|
+
val buffer_l = ShortArray(CHUNK_SIZE)
|
|
117
|
+
val buffer_r = ShortArray(CHUNK_SIZE)
|
|
118
|
+
val mp3Buf = ByteArray(CHUNK_SIZE)
|
|
119
|
+
|
|
120
|
+
val channels = waveReader!!.channels
|
|
121
|
+
|
|
122
|
+
addLog("started encoding")
|
|
123
|
+
while (true) {
|
|
124
|
+
try {
|
|
125
|
+
if (channels == 2) {
|
|
334
126
|
|
|
335
|
-
|
|
336
|
-
|
|
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
|
|
427
|
-
}
|
|
127
|
+
bytesRead = waveReader!!.read(buffer_l, buffer_r, CHUNK_SIZE)
|
|
128
|
+
addLog("bytes read=$bytesRead")
|
|
428
129
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
130
|
+
if (bytesRead > 0) {
|
|
131
|
+
|
|
132
|
+
var bytesEncoded = 0
|
|
133
|
+
bytesEncoded = androidLame.encode(buffer_l, buffer_r, bytesRead, mp3Buf)
|
|
134
|
+
addLog("bytes encoded=$bytesEncoded")
|
|
135
|
+
|
|
136
|
+
if (bytesEncoded > 0) {
|
|
137
|
+
try {
|
|
138
|
+
addLog("writing mp3 buffer to outputstream with $bytesEncoded bytes")
|
|
139
|
+
outputStream!!.write(mp3Buf, 0, bytesEncoded)
|
|
140
|
+
} catch (e: IOException) {
|
|
141
|
+
e.printStackTrace()
|
|
441
142
|
}
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
return MEDIATYPE_NOT_AUDIO_VIDEO
|
|
445
|
-
}
|
|
446
143
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
} else
|
|
147
|
+
break
|
|
148
|
+
} else {
|
|
149
|
+
|
|
150
|
+
bytesRead = waveReader!!.read(buffer_l, CHUNK_SIZE)
|
|
151
|
+
addLog("bytes read=$bytesRead")
|
|
152
|
+
|
|
153
|
+
if (bytesRead > 0) {
|
|
154
|
+
var bytesEncoded = 0
|
|
155
|
+
|
|
156
|
+
bytesEncoded = androidLame.encode(buffer_l, buffer_l, bytesRead, mp3Buf)
|
|
157
|
+
addLog("bytes encoded=$bytesEncoded")
|
|
158
|
+
|
|
159
|
+
if (bytesEncoded > 0) {
|
|
160
|
+
try {
|
|
161
|
+
addLog("writing mp3 buffer to outputstream with $bytesEncoded bytes")
|
|
162
|
+
outputStream!!.write(mp3Buf, 0, bytesEncoded)
|
|
163
|
+
} catch (e: IOException) {
|
|
164
|
+
e.printStackTrace()
|
|
456
165
|
}
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
return null
|
|
460
|
-
}
|
|
461
166
|
|
|
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...")
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
} else
|
|
170
|
+
break
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
481
174
|
} catch (e: IOException) {
|
|
482
|
-
|
|
175
|
+
e.printStackTrace()
|
|
483
176
|
}
|
|
177
|
+
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
addLog("flushing final mp3buffer")
|
|
181
|
+
val outputMp3buf = androidLame.flush(mp3Buf)
|
|
182
|
+
addLog("flushed $outputMp3buf bytes")
|
|
183
|
+
|
|
184
|
+
if (outputMp3buf > 0) {
|
|
484
185
|
try {
|
|
485
|
-
|
|
186
|
+
addLog("writing final mp3buffer to outputstream")
|
|
187
|
+
outputStream!!.write(mp3Buf, 0, outputMp3buf)
|
|
188
|
+
addLog("closing output stream")
|
|
189
|
+
outputStream!!.close()
|
|
190
|
+
completeCallback(output.absolutePath, true)
|
|
486
191
|
} catch (e: IOException) {
|
|
487
|
-
|
|
192
|
+
completeCallback(e.localizedMessage, false)
|
|
193
|
+
e.printStackTrace()
|
|
488
194
|
}
|
|
489
|
-
|
|
490
|
-
mDecoder!!.start()
|
|
491
|
-
// mTrackIndex = -1;
|
|
492
|
-
}
|
|
195
|
+
}
|
|
493
196
|
|
|
494
|
-
|
|
495
|
-
|
|
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
|
-
}
|
|
197
|
+
} catch (e: IOException) {
|
|
198
|
+
completeCallback(e.localizedMessage, false)
|
|
199
|
+
}
|
|
519
200
|
}
|
|
520
201
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
const val MIME_TYPE = MediaFormat.MIMETYPE_AUDIO_AAC
|
|
525
|
-
private const val MEDIATYPE_NOT_AUDIO_VIDEO = -233
|
|
526
|
-
}
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
}
|
|
527
205
|
}
|