@@ -2,6 +2,7 @@ package com.record.upload.extension
2
2
3
3
import android.content.ContentUris
4
4
import android.content.Context
5
+ import android.graphics.Bitmap
5
6
import android.media.MediaMetadataRetriever
6
7
import android.net.Uri
7
8
import android.provider.MediaStore
@@ -12,8 +13,6 @@ import com.abedelazizshe.lightcompressorlibrary.VideoQuality
12
13
import com.abedelazizshe.lightcompressorlibrary.config.Configuration
13
14
import com.abedelazizshe.lightcompressorlibrary.config.SaveLocation
14
15
import com.abedelazizshe.lightcompressorlibrary.config.SharedStorageConfiguration
15
- import com.arthenica.mobileffmpeg.Config
16
- import com.arthenica.mobileffmpeg.FFmpeg
17
16
import kotlinx.coroutines.CoroutineScope
18
17
import kotlinx.coroutines.Dispatchers
19
18
import kotlinx.coroutines.launch
@@ -22,6 +21,7 @@ import okhttp3.OkHttpClient
22
21
import okhttp3.Request
23
22
import okhttp3.RequestBody
24
23
import java.io.File
24
+ import java.io.FileOutputStream
25
25
import java.io.IOException
26
26
27
27
fun getAllVideos (
@@ -166,52 +166,8 @@ fun formatDuration(durationMillis: Long): String {
166
166
return String .format(" %d:%02d" , minutes, seconds)
167
167
}
168
168
169
- fun getVideoEncodingInfo (context : Context , videoFile : File ) {
170
- val retriever = MediaMetadataRetriever ()
171
- try {
172
- retriever.setDataSource(context, Uri .fromFile(videoFile))
173
- val mimeType = retriever.extractMetadata(MediaMetadataRetriever .METADATA_KEY_MIMETYPE )
174
- val duration = retriever.extractMetadata(MediaMetadataRetriever .METADATA_KEY_DURATION )
175
- val width = retriever.extractMetadata(MediaMetadataRetriever .METADATA_KEY_VIDEO_WIDTH )
176
- val height = retriever.extractMetadata(MediaMetadataRetriever .METADATA_KEY_VIDEO_HEIGHT )
177
- val bitrate = retriever.extractMetadata(MediaMetadataRetriever .METADATA_KEY_BITRATE )
178
-
179
- Log .d(" VideoInfo" , " MIME Type: $mimeType " )
180
- Log .d(" VideoInfo" , " Duration: $duration ms" )
181
- Log .d(" VideoInfo" , " Width: $width pixels" )
182
- Log .d(" VideoInfo" , " Height: $height pixels" )
183
- Log .d(" VideoInfo" , " Bitrate: $bitrate bps" )
184
- } catch (e: Exception ) {
185
- e.printStackTrace()
186
- } finally {
187
- retriever.release()
188
- }
189
- }
190
-
191
- fun reencodeVideo (inputFile : File , outputFile : File , callback : (Boolean , String ) -> Unit ) {
192
- val command = arrayOf(
193
- " -i" , inputFile.absolutePath,
194
- " -c:v" , " libx264" , // 비디오 코덱 설정
195
- " -b:v" , " 1000k" , // 비디오 비트레이트 설정
196
- " -c:a" , " aac" , // 오디오 코덱 설정
197
- " -b:a" , " 192k" , // 오디오 비트레이트 설정
198
- " -movflags" , " faststart" , // 웹 스트리밍을 위해 메타데이터를 파일의 시작 부분에 배치
199
- outputFile.absolutePath
200
- )
201
- Config .setLogLevel(Config .getLogLevel())
202
- Config .enableLogCallback { logMessage ->
203
- Log .d(" FFmpegLog" , logMessage.text)
204
- }
205
- FFmpeg .executeAsync(command) { executionId, returnCode ->
206
- if (returnCode == Config .RETURN_CODE_SUCCESS ) {
207
- callback(true , " Re-encoding successful" )
208
- } else {
209
- callback(false , " Re-encoding failed with return code $returnCode " )
210
- }
211
- }
212
- }
213
-
214
169
fun uploadFileToS3PresignedUrl (presignedUrl : String , file : File , callback : (Boolean , String ) -> Unit ) {
170
+
215
171
val client = OkHttpClient ()
216
172
val mediaType = " application/octet-stream" .toMediaTypeOrNull()
217
173
val requestBody = RequestBody .create(mediaType, file)
@@ -236,49 +192,62 @@ fun uploadFileToS3PresignedUrl(presignedUrl: String, file: File, callback: (Bool
236
192
})
237
193
}
238
194
239
- fun extractAndUploadThumbnail (videoFile : File , thumbnailFile : File , presignedUrl : String , callback : (Boolean , String ) -> Unit ) {
240
- val extractCommand = arrayOf(
241
- " ffmpeg" ,
242
- " -i" , videoFile.absolutePath,
243
- " -ss" , " 00:00:01.000" ,
244
- " -vframes" , " 1" ,
245
- thumbnailFile.absolutePath
246
- )
195
+ fun uploadFileToS3ThumbnailPresignedUrl (context : Context ,presignedUrl : String , file : File , callback : (Boolean , String ) -> Unit ) {
196
+ val videoPath = file.absolutePath
197
+ val outputImagePath = File (context.cacheDir," ${ file.name } .jpg" )
198
+ getVideoFrameAt1Sec(videoPath, outputImagePath.absolutePath)
199
+ val client = OkHttpClient ()
200
+ val mediaType = " application/octet-stream" .toMediaTypeOrNull()
201
+ val requestBody = RequestBody .create(mediaType, outputImagePath)
247
202
248
- try {
249
- val process = ProcessBuilder (* extractCommand).start()
250
- process.waitFor()
251
- if (process.exitValue() == 0 ) {
252
- val client = OkHttpClient ()
253
- val mediaType = " image/jpeg" .toMediaTypeOrNull()
254
- val requestBody = RequestBody .create(mediaType, thumbnailFile)
203
+ val request = Request .Builder ()
204
+ .url(presignedUrl)
205
+ .put(requestBody)
206
+ .build()
255
207
256
- val request = Request . Builder ()
257
- .url(presignedUrl)
258
- .put(requestBody )
259
- .build()
208
+ client.newCall( request).enqueue( object : okhttp3. Callback {
209
+ override fun onFailure ( call : okhttp3. Call , e : IOException ) {
210
+ callback( false , " Upload failed: ${e.message} " )
211
+ }
260
212
261
- client.newCall(request).enqueue(object : okhttp3.Callback {
262
- override fun onFailure (call : okhttp3.Call , e : IOException ) {
263
- callback(false , " Upload failed: ${e.message} " )
264
- }
213
+ override fun onResponse (call : okhttp3.Call , response : okhttp3.Response ) {
214
+ if (response.isSuccessful) {
215
+ callback(true , " Upload successful" )
216
+ } else {
217
+ callback(false , " Upload failed: ${response.message} " )
218
+ }
219
+ }
220
+ })
221
+ }
222
+ fun getVideoFrameAt1Sec (videoPath : String , outputImagePath : String ) {
223
+ val retriever = MediaMetadataRetriever ()
224
+ try {
225
+ retriever.setDataSource(videoPath)
226
+ val timeUs = 1 * 1000000 // 1초를 마이크로초로 변환
227
+ val bitmap: Bitmap ? = retriever.getFrameAtTime(timeUs.toLong(), MediaMetadataRetriever .OPTION_CLOSEST_SYNC )
265
228
266
- override fun onResponse (call : okhttp3.Call , response : okhttp3.Response ) {
267
- if (response.isSuccessful) {
268
- callback(true , " Upload successful" )
269
- } else {
270
- callback(false , " Upload failed: ${response.message} " )
271
- }
272
- }
273
- })
274
- } else {
275
- callback(false , " Thumbnail extraction failed with return code ${process.exitValue()} " )
229
+ if (bitmap != null ) {
230
+ saveBitmapAsJpeg(bitmap, outputImagePath)
276
231
}
277
- } catch (e: IOException ) {
278
- e.printStackTrace()
279
- callback(false , " Thumbnail extraction failed with exception: ${e.message} " )
280
- } catch (e: InterruptedException ) {
232
+ } catch (e: Exception ) {
281
233
e.printStackTrace()
282
- callback(false , " Thumbnail extraction failed with exception: ${e.message} " )
234
+ } finally {
235
+ retriever.release()
283
236
}
284
237
}
238
+
239
+ fun saveBitmapAsJpeg (bitmap : Bitmap , outputPath : String ) {
240
+ var out : FileOutputStream ? = null
241
+ try {
242
+ out = FileOutputStream (outputPath)
243
+ bitmap.compress(Bitmap .CompressFormat .JPEG , 90 , out )
244
+ } catch (e: IOException ) {
245
+ e.printStackTrace()
246
+ } finally {
247
+ try {
248
+ out ?.close()
249
+ } catch (e: IOException ) {
250
+ e.printStackTrace()
251
+ }
252
+ }
253
+ }
0 commit comments