react-native-compressor 1.7.1 → 1.8.0

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.
Files changed (128) hide show
  1. package/README.md +40 -15
  2. package/android/build.gradle +8 -0
  3. package/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt +527 -0
  4. package/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt +31 -0
  5. package/android/src/main/java/com/reactnativecompressor/CompressorModule.kt +157 -0
  6. package/android/src/main/java/com/reactnativecompressor/CompressorPackage.kt +34 -0
  7. package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressor.kt +199 -0
  8. package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressorOptions.kt +57 -0
  9. package/android/src/main/java/com/reactnativecompressor/Image/ImageMain.kt +31 -0
  10. package/android/src/main/java/com/reactnativecompressor/Image/ImageSize.kt +3 -0
  11. package/android/src/main/java/com/reactnativecompressor/Utils/Downloader.kt +119 -0
  12. package/android/src/main/java/com/reactnativecompressor/Utils/EventEmitterHandler.kt +66 -0
  13. package/android/src/main/java/com/reactnativecompressor/Utils/MediaCache.kt +61 -0
  14. package/android/src/main/java/com/reactnativecompressor/Utils/RealPathUtil.kt +177 -0
  15. package/android/src/main/java/com/reactnativecompressor/Utils/Uploader.kt +117 -0
  16. package/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt +162 -0
  17. package/android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression.kt +63 -0
  18. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.kt +125 -0
  19. package/android/src/main/java/com/reactnativecompressor/Video/VideoMain.kt +86 -0
  20. package/android/src/newarch/CompressorSpec.kt +5 -0
  21. package/android/src/oldarch/CompressorSpec.kt +32 -0
  22. package/ios/Audio/AudioMain.swift +115 -0
  23. package/ios/Compressor-Bridging-Header.h +1 -2
  24. package/ios/Compressor.h +0 -8
  25. package/ios/Compressor.mm +28 -389
  26. package/ios/CompressorManager.swift +96 -0
  27. package/ios/Image/ImageCompressor.swift +354 -0
  28. package/ios/Image/ImageCompressorOptions.swift +93 -0
  29. package/ios/Image/ImageMain.swift +27 -0
  30. package/ios/Utils/Downloader.swift +157 -0
  31. package/ios/Utils/EventEmitterHandler.swift +54 -0
  32. package/ios/Utils/MediaCache.swift +48 -0
  33. package/ios/Utils/Uploader.swift +99 -0
  34. package/ios/Utils/Utils.swift +110 -0
  35. package/ios/Video/{VideoCompressor.swift → VideoMain.swift} +168 -147
  36. package/lib/commonjs/Image/index.js +1 -1
  37. package/lib/commonjs/Image/index.js.map +1 -1
  38. package/lib/commonjs/Main.js +1 -8
  39. package/lib/commonjs/Main.js.map +1 -1
  40. package/lib/commonjs/Spec/NativeCompressor.js.map +1 -1
  41. package/lib/commonjs/Video/index.js +4 -33
  42. package/lib/commonjs/Video/index.js.map +1 -1
  43. package/lib/commonjs/expo-plugin/compressor.js.map +1 -1
  44. package/lib/commonjs/index.js +11 -6
  45. package/lib/commonjs/index.js.map +1 -1
  46. package/lib/commonjs/utils/Downloader.js +38 -0
  47. package/lib/commonjs/utils/Downloader.js.map +1 -0
  48. package/lib/commonjs/utils/Uploader.js +40 -0
  49. package/lib/commonjs/utils/Uploader.js.map +1 -0
  50. package/lib/commonjs/utils/index.js +35 -0
  51. package/lib/commonjs/utils/index.js.map +1 -1
  52. package/lib/module/Image/index.js +1 -1
  53. package/lib/module/Image/index.js.map +1 -1
  54. package/lib/module/Main.js +1 -7
  55. package/lib/module/Main.js.map +1 -1
  56. package/lib/module/Spec/NativeCompressor.js.map +1 -1
  57. package/lib/module/Video/index.js +5 -33
  58. package/lib/module/Video/index.js.map +1 -1
  59. package/lib/module/expo-plugin/compressor.js.map +1 -1
  60. package/lib/module/index.js +6 -6
  61. package/lib/module/index.js.map +1 -1
  62. package/lib/module/utils/Downloader.js +31 -0
  63. package/lib/module/utils/Downloader.js.map +1 -0
  64. package/lib/module/utils/Uploader.js +33 -0
  65. package/lib/module/utils/Uploader.js.map +1 -0
  66. package/lib/module/utils/index.js +2 -0
  67. package/lib/module/utils/index.js.map +1 -1
  68. package/lib/typescript/Image/index.d.ts +4 -0
  69. package/lib/typescript/Image/index.d.ts.map +1 -1
  70. package/lib/typescript/Main.d.ts +1 -2
  71. package/lib/typescript/Main.d.ts.map +1 -1
  72. package/lib/typescript/Spec/NativeCompressor.d.ts +8 -2
  73. package/lib/typescript/Spec/NativeCompressor.d.ts.map +1 -1
  74. package/lib/typescript/Video/index.d.ts +4 -28
  75. package/lib/typescript/Video/index.d.ts.map +1 -1
  76. package/lib/typescript/index.d.ts +5 -4
  77. package/lib/typescript/index.d.ts.map +1 -1
  78. package/lib/typescript/utils/Downloader.d.ts +2 -0
  79. package/lib/typescript/utils/Downloader.d.ts.map +1 -0
  80. package/lib/typescript/utils/Uploader.d.ts +28 -0
  81. package/lib/typescript/utils/Uploader.d.ts.map +1 -0
  82. package/lib/typescript/utils/index.d.ts +2 -1
  83. package/lib/typescript/utils/index.d.ts.map +1 -1
  84. package/package.json +6 -4
  85. package/src/Image/index.tsx +5 -1
  86. package/src/Main.tsx +1 -15
  87. package/src/Spec/NativeCompressor.ts +14 -2
  88. package/src/Video/index.tsx +11 -84
  89. package/src/expo-plugin/compressor.ts +1 -1
  90. package/src/index.tsx +6 -3
  91. package/src/utils/Downloader.tsx +38 -0
  92. package/src/utils/Uploader.tsx +78 -0
  93. package/src/utils/index.tsx +2 -0
  94. package/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.java +0 -605
  95. package/android/src/main/java/com/reactnativecompressor/CompressorModule.java +0 -220
  96. package/android/src/main/java/com/reactnativecompressor/CompressorPackage.java +0 -58
  97. package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressor.java +0 -257
  98. package/android/src/main/java/com/reactnativecompressor/Image/utils/ImageCompressorOptions.java +0 -69
  99. package/android/src/main/java/com/reactnativecompressor/Image/utils/ImageSize.java +0 -13
  100. package/android/src/main/java/com/reactnativecompressor/Utils/FileUplaoder/FileUploadHelper.java +0 -39
  101. package/android/src/main/java/com/reactnativecompressor/Utils/FileUplaoder/FileUploader.java +0 -129
  102. package/android/src/main/java/com/reactnativecompressor/Utils/MediaCache.java +0 -65
  103. package/android/src/main/java/com/reactnativecompressor/Utils/RealPathUtil.java +0 -210
  104. package/android/src/main/java/com/reactnativecompressor/Utils/Utils.java +0 -272
  105. package/android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression/AutoVideoCompression.java +0 -87
  106. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.java +0 -182
  107. package/android/src/main/java/com/reactnativecompressor/Video/VideoModule.java +0 -112
  108. package/android/src/newarch/CompressorSpec.java +0 -9
  109. package/android/src/newarch/VideoCompressorSpec.java +0 -9
  110. package/android/src/oldarch/CompressorSpec.java +0 -34
  111. package/android/src/oldarch/VideoCompressorSpec.java +0 -26
  112. package/ios/Image/ImageCompressor.h +0 -22
  113. package/ios/Image/ImageCompressor.m +0 -540
  114. package/ios/Image/ImageCompressorOptions.h +0 -28
  115. package/ios/Image/ImageCompressorOptions.m +0 -97
  116. package/ios/Utils/Downloader.h +0 -16
  117. package/ios/Utils/Downloader.m +0 -150
  118. package/ios/Utils/MediaCache.h +0 -11
  119. package/ios/Utils/MediaCache.m +0 -51
  120. package/ios/Video/VideoCompressor.h +0 -5
  121. package/ios/Video/VideoCompressor.m +0 -1
  122. package/lib/commonjs/Spec/NativeVideoCompressor.js +0 -10
  123. package/lib/commonjs/Spec/NativeVideoCompressor.js.map +0 -1
  124. package/lib/module/Spec/NativeVideoCompressor.js +0 -3
  125. package/lib/module/Spec/NativeVideoCompressor.js.map +0 -1
  126. package/lib/typescript/Spec/NativeVideoCompressor.d.ts +0 -13
  127. package/lib/typescript/Spec/NativeVideoCompressor.d.ts.map +0 -1
  128. package/src/Spec/NativeVideoCompressor.ts +0 -14
@@ -0,0 +1,527 @@
1
+ package com.reactnativecompressor.Audio
2
+
3
+ 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 numan.dev.videocompressor.codecinputsurface.CodecInputSurface
15
+ import java.io.File
16
+ import java.io.IOException
17
+ import java.nio.ByteBuffer
18
+
19
+ 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: CodecInputSurface? = 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
44
+ }
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
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
267
+ }
268
+ Log.e(TAG, "time = " + (System.currentTimeMillis() - time))
269
+ }
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
+
277
+ private fun checkParmsError(sourcePath: String?, destinationPath: String?, nbitrate: Int): Boolean {
278
+ return if (nbitrate <= 0) true else false
279
+ }
280
+
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)
297
+ }
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
331
+ }
332
+ return -1
333
+ }
334
+
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
427
+ }
428
+
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
441
+ }
442
+ }
443
+ }
444
+ return MEDIATYPE_NOT_AUDIO_VIDEO
445
+ }
446
+
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
456
+ }
457
+ }
458
+ }
459
+ return null
460
+ }
461
+
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...")
481
+ } catch (e: IOException) {
482
+ e.printStackTrace()
483
+ }
484
+ try {
485
+ mDecoder = MediaCodec.createDecoderByType(format.getString(MediaFormat.KEY_MIME)!!)
486
+ } catch (e: IOException) {
487
+ e.printStackTrace()
488
+ }
489
+ mDecoder!!.configure(format, null, null, 0)
490
+ mDecoder!!.start()
491
+ // mTrackIndex = -1;
492
+ }
493
+
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
+
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
+ }
527
+ }
@@ -0,0 +1,31 @@
1
+ package com.reactnativecompressor.Audio
2
+
3
+ import android.media.MediaMetadataRetriever
4
+ import android.net.Uri
5
+ import android.util.Log
6
+ import com.facebook.react.bridge.Promise
7
+ import com.facebook.react.bridge.ReactApplicationContext
8
+ import com.facebook.react.bridge.ReadableMap
9
+ import com.reactnativecompressor.Utils.Utils
10
+ import com.reactnativecompressor.Video.VideoCompressorHelper
11
+
12
+ class AudioMain(private val reactContext: ReactApplicationContext) {
13
+ fun compress_audio(
14
+ fileUrl: String,
15
+ optionMap: ReadableMap,
16
+ promise: Promise) {
17
+ try {
18
+ val options = VideoCompressorHelper.fromMap(optionMap)
19
+ val uri = Uri.parse(fileUrl)
20
+ val srcPath = uri.path
21
+ val destinationPath = Utils.generateCacheFilePath("mp3", reactContext)
22
+ val metaRetriever = MediaMetadataRetriever()
23
+ metaRetriever.setDataSource(srcPath)
24
+ val bitrate = options.bitrate
25
+ Log.d("nomi onStart", destinationPath + "onProgress: " + bitrate)
26
+ AudioCompressor().CompressAudio(srcPath, destinationPath, bitrate.toInt() * 1000)
27
+ } catch (ex: Exception) {
28
+ promise.reject(ex)
29
+ }
30
+ }
31
+ }