react-native-compressor 1.7.2 → 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 +30 -7
  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} +167 -146
  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
package/README.md CHANGED
@@ -17,9 +17,9 @@
17
17
  **REACT-NATIVE-COMPRESSOR** is a react-native package, which helps us to Compress `Image`, `Video`, and `Audio` before uploading, same like **Whatsapp** without knowing the compression `algorithm`
18
18
 
19
19
  <div align="center">
20
- <img height="90" src="/media/whatsapp_logo.png"/>
21
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
22
- <img height="90" src="/media/compress_media.png"/>
20
+ <pre>
21
+ <img height="90" src="/media/whatsapp_logo.png"/> <img height="90" src="/media/compress_media.png"/>
22
+ </pre>
23
23
  <h2 align="center">🗜️Compress Image, Video, and Audio same like Whatsapp</h2>
24
24
  </div>
25
25
 
@@ -53,9 +53,7 @@ We should use **react-native-compressor** instead of **FFmpeg** because **react-
53
53
  <summary>Open Table of Contents</summary>
54
54
 
55
55
  - [Installation](#installation)
56
- - [For React Native](#react-native)
57
- - [For React Native<0.65](#for-react-native065)
58
- - [For React Native 0.65 or greater](#for-react-native-065-or-greater)
56
+ - [For React Native](#Installation)
59
57
  - [Managed Expo](#managed-expo)
60
58
  - [Usage](#usage)
61
59
  - [Image](#image)
@@ -69,6 +67,7 @@ We should use **react-native-compressor** instead of **FFmpeg** because **react-
69
67
  - [Video Api Docs](#video-1)
70
68
  - [Audio](#audio)
71
69
  - [Background Upload](#background-upload)
70
+ - [Download File](#download)
72
71
 
73
72
  * [Other Utilities](#api)
74
73
  - [Background Upload](#background-upload-1)
@@ -164,6 +163,7 @@ import { Image } from 'react-native-compressor';
164
163
  const result = await Image.compress('file://path_of_file/image.jpg');
165
164
  // OR
166
165
  const result = await Image.compress('https://path_of_file/image.jpg', {
166
+ progressDivider: 10,
167
167
  downloadProgress: (progress) => {
168
168
  console.log('downloadProgress: ', progress);
169
169
  },
@@ -204,6 +204,7 @@ const result = await Video.compress(
204
204
  const result = await Video.compress(
205
205
  'https://example.com/video.mp4',
206
206
  {
207
+ progressDivider: 10,
207
208
  downloadProgress: (progress) => {
208
209
  console.log('downloadProgress: ', progress);
209
210
  },
@@ -288,6 +289,16 @@ const uploadResult = await backgroundUpload(
288
289
  );
289
290
  ```
290
291
 
292
+ ### Download File
293
+
294
+ ```js
295
+ import { download } from 'react-native-compressor';
296
+
297
+ const downloadFileUrl = await download(url, (progress) => {
298
+ console.log('downloadProgress: ', progress);
299
+ });
300
+ ```
301
+
291
302
  # API
292
303
 
293
304
  ## Image
@@ -308,6 +319,10 @@ const uploadResult = await backgroundUpload(
308
319
 
309
320
  it is callback, only trigger when we pass image url from server
310
321
 
322
+ - ##### `progressDivider?: number` (default: 0)
323
+
324
+ we uses it when we use downloadProgress
325
+
311
326
  - ###### `maxWidth: number` (default: 1280)
312
327
 
313
328
  The maximum width boundary used as the main boundary in resizing a landscape image.
@@ -348,6 +363,10 @@ const uploadResult = await backgroundUpload(
348
363
 
349
364
  it is callback, only trigger when we pass image url from server
350
365
 
366
+ - ##### `progressDivider?: number` (default: 0)
367
+
368
+ we uses it when we use downloadProgress/onProgress
369
+
351
370
  - ###### `maxSize: number` (default: 640)
352
371
 
353
372
  The maximum size can be height in case of portrait video or can be width in case of landscape video.
@@ -376,7 +395,7 @@ const uploadResult = await backgroundUpload(
376
395
 
377
396
  ## Background Upload
378
397
 
379
- - ###### `backgroundUpload: (url: string, fileUrl: string, options: FileSystemUploadOptions, onProgress?: ((writtem: number, total: number) => void) | undefined) => Promise<any>
398
+ - ###### backgroundUpload: (url: string, fileUrl: string, options: FileSystemUploadOptions, onProgress?: ((writtem: number, total: number) => void) | undefined) => Promise< any >
380
399
 
381
400
  - ###### ` FileSystemUploadOptions`
382
401
 
@@ -398,6 +417,10 @@ type FileSystemUploadOptions = (
398
417
  };
399
418
  ```
400
419
 
420
+ ### Download
421
+
422
+ - ##### download: ( fileUrl: string, downloadProgress?: (progress: number) => void, progressDivider?: number ) => Promise< string >
423
+
401
424
  ### Get Metadata Of Video
402
425
 
403
426
  if you want to get metadata of video than you can use this function
@@ -1,4 +1,7 @@
1
1
  buildscript {
2
+ // Buildscript is evaluated before everything else so we can't use getExtOrDefault
3
+ def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["Compressor_kotlinVersion"]
4
+
2
5
  repositories {
3
6
  google()
4
7
  mavenCentral()
@@ -6,6 +9,8 @@ buildscript {
6
9
 
7
10
  dependencies {
8
11
  classpath "com.android.tools.build:gradle:7.2.1"
12
+ // noinspection DifferentKotlinGradleVersion
13
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
9
14
  }
10
15
  }
11
16
 
@@ -14,6 +19,7 @@ def isNewArchitectureEnabled() {
14
19
  }
15
20
 
16
21
  apply plugin: "com.android.library"
22
+ apply plugin: "kotlin-android"
17
23
 
18
24
 
19
25
  def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
@@ -96,12 +102,14 @@ repositories {
96
102
  google()
97
103
  }
98
104
 
105
+ def kotlin_version = getExtOrDefault("kotlinVersion")
99
106
 
100
107
  dependencies {
101
108
  // For < 0.71, this will be from the local maven repo
102
109
  // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
103
110
  //noinspection GradleDynamicVersion
104
111
  implementation "com.facebook.react:react-native:+"
112
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
105
113
  implementation 'io.github.lizhangqu:coreprogress:1.0.2'
106
114
  implementation 'com.github.numandev1:VideoCompressor:1a262bba37'
107
115
  }
@@ -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
+ }