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.
- package/README.md +40 -15
- package/android/build.gradle +8 -0
- package/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.kt +527 -0
- package/android/src/main/java/com/reactnativecompressor/Audio/AudioMain.kt +31 -0
- package/android/src/main/java/com/reactnativecompressor/CompressorModule.kt +157 -0
- package/android/src/main/java/com/reactnativecompressor/CompressorPackage.kt +34 -0
- package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressor.kt +199 -0
- package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressorOptions.kt +57 -0
- package/android/src/main/java/com/reactnativecompressor/Image/ImageMain.kt +31 -0
- package/android/src/main/java/com/reactnativecompressor/Image/ImageSize.kt +3 -0
- package/android/src/main/java/com/reactnativecompressor/Utils/Downloader.kt +119 -0
- package/android/src/main/java/com/reactnativecompressor/Utils/EventEmitterHandler.kt +66 -0
- package/android/src/main/java/com/reactnativecompressor/Utils/MediaCache.kt +61 -0
- package/android/src/main/java/com/reactnativecompressor/Utils/RealPathUtil.kt +177 -0
- package/android/src/main/java/com/reactnativecompressor/Utils/Uploader.kt +117 -0
- package/android/src/main/java/com/reactnativecompressor/Utils/Utils.kt +162 -0
- package/android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression.kt +63 -0
- package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.kt +125 -0
- package/android/src/main/java/com/reactnativecompressor/Video/VideoMain.kt +86 -0
- package/android/src/newarch/CompressorSpec.kt +5 -0
- package/android/src/oldarch/CompressorSpec.kt +32 -0
- package/ios/Audio/AudioMain.swift +115 -0
- package/ios/Compressor-Bridging-Header.h +1 -2
- package/ios/Compressor.h +0 -8
- package/ios/Compressor.mm +28 -389
- package/ios/CompressorManager.swift +96 -0
- package/ios/Image/ImageCompressor.swift +354 -0
- package/ios/Image/ImageCompressorOptions.swift +93 -0
- package/ios/Image/ImageMain.swift +27 -0
- package/ios/Utils/Downloader.swift +157 -0
- package/ios/Utils/EventEmitterHandler.swift +54 -0
- package/ios/Utils/MediaCache.swift +48 -0
- package/ios/Utils/Uploader.swift +99 -0
- package/ios/Utils/Utils.swift +110 -0
- package/ios/Video/{VideoCompressor.swift → VideoMain.swift} +168 -147
- package/lib/commonjs/Image/index.js +1 -1
- package/lib/commonjs/Image/index.js.map +1 -1
- package/lib/commonjs/Main.js +1 -8
- package/lib/commonjs/Main.js.map +1 -1
- package/lib/commonjs/Spec/NativeCompressor.js.map +1 -1
- package/lib/commonjs/Video/index.js +4 -33
- package/lib/commonjs/Video/index.js.map +1 -1
- package/lib/commonjs/expo-plugin/compressor.js.map +1 -1
- package/lib/commonjs/index.js +11 -6
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/utils/Downloader.js +38 -0
- package/lib/commonjs/utils/Downloader.js.map +1 -0
- package/lib/commonjs/utils/Uploader.js +40 -0
- package/lib/commonjs/utils/Uploader.js.map +1 -0
- package/lib/commonjs/utils/index.js +35 -0
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/module/Image/index.js +1 -1
- package/lib/module/Image/index.js.map +1 -1
- package/lib/module/Main.js +1 -7
- package/lib/module/Main.js.map +1 -1
- package/lib/module/Spec/NativeCompressor.js.map +1 -1
- package/lib/module/Video/index.js +5 -33
- package/lib/module/Video/index.js.map +1 -1
- package/lib/module/expo-plugin/compressor.js.map +1 -1
- package/lib/module/index.js +6 -6
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/Downloader.js +31 -0
- package/lib/module/utils/Downloader.js.map +1 -0
- package/lib/module/utils/Uploader.js +33 -0
- package/lib/module/utils/Uploader.js.map +1 -0
- package/lib/module/utils/index.js +2 -0
- package/lib/module/utils/index.js.map +1 -1
- package/lib/typescript/Image/index.d.ts +4 -0
- package/lib/typescript/Image/index.d.ts.map +1 -1
- package/lib/typescript/Main.d.ts +1 -2
- package/lib/typescript/Main.d.ts.map +1 -1
- package/lib/typescript/Spec/NativeCompressor.d.ts +8 -2
- package/lib/typescript/Spec/NativeCompressor.d.ts.map +1 -1
- package/lib/typescript/Video/index.d.ts +4 -28
- package/lib/typescript/Video/index.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +5 -4
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/utils/Downloader.d.ts +2 -0
- package/lib/typescript/utils/Downloader.d.ts.map +1 -0
- package/lib/typescript/utils/Uploader.d.ts +28 -0
- package/lib/typescript/utils/Uploader.d.ts.map +1 -0
- package/lib/typescript/utils/index.d.ts +2 -1
- package/lib/typescript/utils/index.d.ts.map +1 -1
- package/package.json +6 -4
- package/src/Image/index.tsx +5 -1
- package/src/Main.tsx +1 -15
- package/src/Spec/NativeCompressor.ts +14 -2
- package/src/Video/index.tsx +11 -84
- package/src/expo-plugin/compressor.ts +1 -1
- package/src/index.tsx +6 -3
- package/src/utils/Downloader.tsx +38 -0
- package/src/utils/Uploader.tsx +78 -0
- package/src/utils/index.tsx +2 -0
- package/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.java +0 -605
- package/android/src/main/java/com/reactnativecompressor/CompressorModule.java +0 -220
- package/android/src/main/java/com/reactnativecompressor/CompressorPackage.java +0 -58
- package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressor.java +0 -257
- package/android/src/main/java/com/reactnativecompressor/Image/utils/ImageCompressorOptions.java +0 -69
- package/android/src/main/java/com/reactnativecompressor/Image/utils/ImageSize.java +0 -13
- package/android/src/main/java/com/reactnativecompressor/Utils/FileUplaoder/FileUploadHelper.java +0 -39
- package/android/src/main/java/com/reactnativecompressor/Utils/FileUplaoder/FileUploader.java +0 -129
- package/android/src/main/java/com/reactnativecompressor/Utils/MediaCache.java +0 -65
- package/android/src/main/java/com/reactnativecompressor/Utils/RealPathUtil.java +0 -210
- package/android/src/main/java/com/reactnativecompressor/Utils/Utils.java +0 -272
- package/android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression/AutoVideoCompression.java +0 -87
- package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.java +0 -182
- package/android/src/main/java/com/reactnativecompressor/Video/VideoModule.java +0 -112
- package/android/src/newarch/CompressorSpec.java +0 -9
- package/android/src/newarch/VideoCompressorSpec.java +0 -9
- package/android/src/oldarch/CompressorSpec.java +0 -34
- package/android/src/oldarch/VideoCompressorSpec.java +0 -26
- package/ios/Image/ImageCompressor.h +0 -22
- package/ios/Image/ImageCompressor.m +0 -540
- package/ios/Image/ImageCompressorOptions.h +0 -28
- package/ios/Image/ImageCompressorOptions.m +0 -97
- package/ios/Utils/Downloader.h +0 -16
- package/ios/Utils/Downloader.m +0 -150
- package/ios/Utils/MediaCache.h +0 -11
- package/ios/Utils/MediaCache.m +0 -51
- package/ios/Video/VideoCompressor.h +0 -5
- package/ios/Video/VideoCompressor.m +0 -1
- package/lib/commonjs/Spec/NativeVideoCompressor.js +0 -10
- package/lib/commonjs/Spec/NativeVideoCompressor.js.map +0 -1
- package/lib/module/Spec/NativeVideoCompressor.js +0 -3
- package/lib/module/Spec/NativeVideoCompressor.js.map +0 -1
- package/lib/typescript/Spec/NativeVideoCompressor.d.ts +0 -13
- package/lib/typescript/Spec/NativeVideoCompressor.d.ts.map +0 -1
- 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
|
+
}
|