|
|
|
@ -13,7 +13,9 @@ import android.provider.MediaStore |
|
|
|
import androidx.core.content.FileProvider |
|
|
|
import androidx.core.content.FileProvider |
|
|
|
import com.arthenica.ffmpegkit.FFmpegKit |
|
|
|
import com.arthenica.ffmpegkit.FFmpegKit |
|
|
|
import io.realm.Realm |
|
|
|
import io.realm.Realm |
|
|
|
import kotlinx.coroutines.* |
|
|
|
import kotlinx.coroutines.CoroutineScope |
|
|
|
|
|
|
|
import kotlinx.coroutines.Dispatchers |
|
|
|
|
|
|
|
import kotlinx.coroutines.launch |
|
|
|
import net.pokeranalytics.android.R |
|
|
|
import net.pokeranalytics.android.R |
|
|
|
import net.pokeranalytics.android.exceptions.PAIllegalStateException |
|
|
|
import net.pokeranalytics.android.exceptions.PAIllegalStateException |
|
|
|
import net.pokeranalytics.android.model.realm.handhistory.HandHistory |
|
|
|
import net.pokeranalytics.android.model.realm.handhistory.HandHistory |
|
|
|
@ -26,7 +28,6 @@ import timber.log.Timber |
|
|
|
import java.io.File |
|
|
|
import java.io.File |
|
|
|
import java.io.FileOutputStream |
|
|
|
import java.io.FileOutputStream |
|
|
|
import java.util.* |
|
|
|
import java.util.* |
|
|
|
import kotlin.coroutines.CoroutineContext |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum class FileType(var value: String) { |
|
|
|
enum class FileType(var value: String) { |
|
|
|
IMAGE_GIF("image/gif"), |
|
|
|
IMAGE_GIF("image/gif"), |
|
|
|
@ -39,9 +40,6 @@ class ReplayExportService : Service() { |
|
|
|
|
|
|
|
|
|
|
|
private val binder = LocalBinder() |
|
|
|
private val binder = LocalBinder() |
|
|
|
|
|
|
|
|
|
|
|
private val coroutineContext: CoroutineContext |
|
|
|
|
|
|
|
get() = Dispatchers.Main |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun onBind(intent: Intent?): IBinder { |
|
|
|
override fun onBind(intent: Intent?): IBinder { |
|
|
|
return binder |
|
|
|
return binder |
|
|
|
} |
|
|
|
} |
|
|
|
@ -70,13 +68,13 @@ class ReplayExportService : Service() { |
|
|
|
|
|
|
|
|
|
|
|
private fun startGIFExport() { |
|
|
|
private fun startGIFExport() { |
|
|
|
|
|
|
|
|
|
|
|
GlobalScope.launch(coroutineContext) { |
|
|
|
CoroutineScope(Dispatchers.Default).launch { |
|
|
|
val c = GlobalScope.async { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val realm = Realm.getDefaultInstance() |
|
|
|
val realm = Realm.getDefaultInstance() |
|
|
|
realm.refresh() |
|
|
|
realm.refresh() |
|
|
|
|
|
|
|
|
|
|
|
val handHistory = realm.findById<HandHistory>(handHistoryId) ?: throw PAIllegalStateException("HandHistory not found, id: $handHistoryId") |
|
|
|
val handHistory = realm.findById<HandHistory>(handHistoryId) |
|
|
|
|
|
|
|
?: throw PAIllegalStateException("HandHistory not found, id: $handHistoryId") |
|
|
|
|
|
|
|
|
|
|
|
val context = this@ReplayExportService |
|
|
|
val context = this@ReplayExportService |
|
|
|
|
|
|
|
|
|
|
|
@ -96,7 +94,8 @@ class ReplayExportService : Service() { |
|
|
|
val resolver = applicationContext.contentResolver |
|
|
|
val resolver = applicationContext.contentResolver |
|
|
|
|
|
|
|
|
|
|
|
// Q version tested before calling the function |
|
|
|
// Q version tested before calling the function |
|
|
|
val imageCollection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) |
|
|
|
val imageCollection = |
|
|
|
|
|
|
|
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) |
|
|
|
|
|
|
|
|
|
|
|
val gifDetails = ContentValues().apply { |
|
|
|
val gifDetails = ContentValues().apply { |
|
|
|
put(MediaStore.Images.Media.DISPLAY_NAME, fileName) |
|
|
|
put(MediaStore.Images.Media.DISPLAY_NAME, fileName) |
|
|
|
@ -139,18 +138,16 @@ class ReplayExportService : Service() { |
|
|
|
Timber.w("Resolver insert ended without uri...") |
|
|
|
Timber.w("Resolver insert ended without uri...") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
c.await() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fun startFFMPEGVideoExport() { |
|
|
|
private fun startFFMPEGVideoExport() { |
|
|
|
|
|
|
|
|
|
|
|
GlobalScope.launch(coroutineContext) { |
|
|
|
CoroutineScope(Dispatchers.Default).launch { |
|
|
|
val async = GlobalScope.async { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val realm = Realm.getDefaultInstance() |
|
|
|
val realm = Realm.getDefaultInstance() |
|
|
|
val handHistory = realm.findById<HandHistory>(handHistoryId) ?: throw PAIllegalStateException("HandHistory not found, id: $handHistoryId") |
|
|
|
val handHistory = realm.findById<HandHistory>(handHistoryId) |
|
|
|
|
|
|
|
?: throw PAIllegalStateException("HandHistory not found, id: $handHistoryId") |
|
|
|
|
|
|
|
|
|
|
|
val context = this@ReplayExportService |
|
|
|
val context = this@ReplayExportService |
|
|
|
|
|
|
|
|
|
|
|
@ -173,12 +170,14 @@ class ReplayExportService : Service() { |
|
|
|
val formattedDate = Date().dateTimeFileFormatted |
|
|
|
val formattedDate = Date().dateTimeFileFormatted |
|
|
|
val fileName = "hand_${formattedDate}.mp4" |
|
|
|
val fileName = "hand_${formattedDate}.mp4" |
|
|
|
|
|
|
|
|
|
|
|
val outputDirectory = context.getExternalFilesDir(Environment.DIRECTORY_MOVIES) ?: throw PAIllegalStateException("File is invalid") |
|
|
|
val outputDirectory = context.getExternalFilesDir(Environment.DIRECTORY_MOVIES) |
|
|
|
|
|
|
|
?: throw PAIllegalStateException("File is invalid") |
|
|
|
val output = "${outputDirectory.path}/$fileName" |
|
|
|
val output = "${outputDirectory.path}/$fileName" |
|
|
|
|
|
|
|
|
|
|
|
Timber.d("Assembling images for video...") |
|
|
|
Timber.d("Assembling images for video...") |
|
|
|
|
|
|
|
|
|
|
|
val command = "-f concat -safe 0 -i $dpath -vb 20M -vsync vfr -s ${width}x${height} -vf fps=20 -pix_fmt yuv420p $output" |
|
|
|
val command = |
|
|
|
|
|
|
|
"-f concat -safe 0 -i $dpath -vb 20M -vsync vfr -s ${width}x${height} -vf fps=20 -pix_fmt yuv420p $output" |
|
|
|
FFmpegKit.executeAsync(command) { |
|
|
|
FFmpegKit.executeAsync(command) { |
|
|
|
|
|
|
|
|
|
|
|
when { |
|
|
|
when { |
|
|
|
@ -189,7 +188,7 @@ class ReplayExportService : Service() { |
|
|
|
Timber.d("Command execution cancelled by user.") |
|
|
|
Timber.d("Command execution cancelled by user.") |
|
|
|
} |
|
|
|
} |
|
|
|
else -> { |
|
|
|
else -> { |
|
|
|
Timber.d(String.format("Command execution failed with rc=%d and the output below.", it.returnCode.value)) |
|
|
|
Timber.d("Command execution failed with rc=${it.returnCode.value} and the output below.") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -201,7 +200,8 @@ class ReplayExportService : Service() { |
|
|
|
val resolver = applicationContext.contentResolver |
|
|
|
val resolver = applicationContext.contentResolver |
|
|
|
|
|
|
|
|
|
|
|
// Q version tested before calling the function |
|
|
|
// Q version tested before calling the function |
|
|
|
val videoCollection = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) |
|
|
|
val videoCollection = |
|
|
|
|
|
|
|
MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) |
|
|
|
|
|
|
|
|
|
|
|
val fileDetails = ContentValues().apply { |
|
|
|
val fileDetails = ContentValues().apply { |
|
|
|
Timber.d("set file details = $fileName") |
|
|
|
Timber.d("set file details = $fileName") |
|
|
|
@ -229,66 +229,18 @@ class ReplayExportService : Service() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
async.await() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// private fun startVideoExport() { |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// GlobalScope.launch(coroutineContext) { |
|
|
|
|
|
|
|
// val c = GlobalScope.async { |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// val realm = Realm.getDefaultInstance() |
|
|
|
|
|
|
|
// val handHistory = realm.findById<HandHistory>(handHistoryId) ?: throw PAIllegalStateException("HandHistory not found, id: $handHistoryId") |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// val context = this@ReplayExportService |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// val animator = ReplayerAnimator(handHistory, true) |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// val square = 1024 |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// val width = square |
|
|
|
|
|
|
|
// val height = square |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// animator.setDimension(width.toFloat(), height.toFloat()) |
|
|
|
|
|
|
|
// TableDrawer.configurePaints(context, animator) |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// val muxer = MMediaMuxer() |
|
|
|
|
|
|
|
// muxer.init(null, width, height, "hhVideo", "YES!") |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// animator.frames(context) { bitmap, count -> |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// try { |
|
|
|
|
|
|
|
// val byteArray = bitmap.toByteArray() |
|
|
|
|
|
|
|
// muxer.addFrame(byteArray, count, false) |
|
|
|
|
|
|
|
// } catch (e: Exception) { |
|
|
|
|
|
|
|
// Timber.e("error = ${e.message}") |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// realm.close() |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// muxer.createVideo { path -> |
|
|
|
|
|
|
|
// notifyUser(path) |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// c.await() |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun startGIFExportPreQ() { |
|
|
|
private fun startGIFExportPreQ() { |
|
|
|
|
|
|
|
|
|
|
|
GlobalScope.launch(coroutineContext) { |
|
|
|
CoroutineScope(Dispatchers.Default).launch { |
|
|
|
val c = GlobalScope.async { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val realm = Realm.getDefaultInstance() |
|
|
|
val realm = Realm.getDefaultInstance() |
|
|
|
realm.refresh() |
|
|
|
realm.refresh() |
|
|
|
|
|
|
|
|
|
|
|
val handHistory = realm.findById<HandHistory>(handHistoryId) ?: throw PAIllegalStateException("HandHistory not found, id: $handHistoryId") |
|
|
|
val handHistory = realm.findById<HandHistory>(handHistoryId) |
|
|
|
|
|
|
|
?: throw PAIllegalStateException("HandHistory not found, id: $handHistoryId") |
|
|
|
|
|
|
|
|
|
|
|
val context = this@ReplayExportService |
|
|
|
val context = this@ReplayExportService |
|
|
|
|
|
|
|
|
|
|
|
@ -337,18 +289,16 @@ class ReplayExportService : Service() { |
|
|
|
notifyUser(path) |
|
|
|
notifyUser(path) |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
c.await() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fun startFFMPEGVideoExportPreQ() { |
|
|
|
private fun startFFMPEGVideoExportPreQ() { |
|
|
|
|
|
|
|
|
|
|
|
GlobalScope.launch(coroutineContext) { |
|
|
|
CoroutineScope(Dispatchers.Default).launch { |
|
|
|
val async = GlobalScope.async { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val realm = Realm.getDefaultInstance() |
|
|
|
val realm = Realm.getDefaultInstance() |
|
|
|
val handHistory = realm.findById<HandHistory>(handHistoryId) ?: throw PAIllegalStateException("HandHistory not found, id: $handHistoryId") |
|
|
|
val handHistory = realm.findById<HandHistory>(handHistoryId) |
|
|
|
|
|
|
|
?: throw PAIllegalStateException("HandHistory not found, id: $handHistoryId") |
|
|
|
|
|
|
|
|
|
|
|
val context = this@ReplayExportService |
|
|
|
val context = this@ReplayExportService |
|
|
|
|
|
|
|
|
|
|
|
@ -378,8 +328,8 @@ class ReplayExportService : Service() { |
|
|
|
|
|
|
|
|
|
|
|
Timber.d("Assembling images for video...") |
|
|
|
Timber.d("Assembling images for video...") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val command = |
|
|
|
val command = "-f concat -safe 0 -i $dpath -vb 20M -vsync vfr -s ${width}x${height} -vf fps=20 -pix_fmt yuv420p $output" |
|
|
|
"-f concat -safe 0 -i $dpath -vb 20M -vsync vfr -s ${width}x${height} -vf fps=20 -pix_fmt yuv420p $output" |
|
|
|
FFmpegKit.executeAsync(command) { |
|
|
|
FFmpegKit.executeAsync(command) { |
|
|
|
|
|
|
|
|
|
|
|
when { |
|
|
|
when { |
|
|
|
@ -390,7 +340,7 @@ class ReplayExportService : Service() { |
|
|
|
Timber.d("Command execution cancelled by user.") |
|
|
|
Timber.d("Command execution cancelled by user.") |
|
|
|
} |
|
|
|
} |
|
|
|
else -> { |
|
|
|
else -> { |
|
|
|
Timber.d(String.format("Command execution failed with rc=%d and the output below.", it.returnCode.value)) |
|
|
|
Timber.d("Command execution failed with rc=${it.returnCode.value} and the output below.") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -411,8 +361,6 @@ class ReplayExportService : Service() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
async.await() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -454,7 +402,8 @@ class ReplayExportService : Service() { |
|
|
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) |
|
|
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) |
|
|
|
val chooser = Intent.createChooser(intent, getString(R.string.open_file_with)) |
|
|
|
val chooser = Intent.createChooser(intent, getString(R.string.open_file_with)) |
|
|
|
|
|
|
|
|
|
|
|
val pendingIntent = PendingIntent.getActivity(this, 0, chooser, PendingIntent.FLAG_CANCEL_CURRENT) |
|
|
|
val pendingIntent = |
|
|
|
|
|
|
|
PendingIntent.getActivity(this, 0, chooser, PendingIntent.FLAG_CANCEL_CURRENT) |
|
|
|
|
|
|
|
|
|
|
|
TriggerNotification(this, title, body, pendingIntent) |
|
|
|
TriggerNotification(this, title, body, pendingIntent) |
|
|
|
|
|
|
|
|
|
|
|
|