Video export code, crashing due to memory allocation

hh
Laurent 5 years ago
parent a18e180f07
commit f502374967
  1. 2
      app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/HandHistory.kt
  2. 6
      app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt
  3. 47
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryFragment.kt
  4. 2
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/model/ActionList.kt
  5. 40
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/replayer/ReplayerAnimator.kt
  6. 2
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/replayer/ReplayerFragment.kt
  7. 4
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/replayer/ReplayerModel.kt
  8. 17
      app/src/main/java/net/pokeranalytics/android/util/video/MMediaMuxer.kt

@ -21,7 +21,6 @@ import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.TimeFilterable
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.modules.handhistory.evaluator.EvaluatorBridge
import net.pokeranalytics.android.ui.modules.handhistory.model.ActionList
import net.pokeranalytics.android.ui.modules.handhistory.model.ActionReadRow
import net.pokeranalytics.android.ui.modules.handhistory.model.CardHolder
import net.pokeranalytics.android.ui.view.RowRepresentable
@ -30,7 +29,6 @@ import net.pokeranalytics.android.util.extensions.addLineReturn
import net.pokeranalytics.android.util.extensions.formatted
import net.pokeranalytics.android.util.extensions.fullDate
import java.util.*
import kotlin.Comparator
import kotlin.math.max
data class PositionAmount(var position: Int, var amount: Double, var isAllin: Boolean)

@ -466,9 +466,9 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
*/
private fun createNewHandHistory() {
val intent = Intent(requireContext(), TestActivity::class.java)
startActivity(intent)
return
// val intent = Intent(requireContext(), TestActivity::class.java)
// startActivity(intent)
// return
AppGuard.endOfUse?.let { endDate ->

@ -1,10 +1,12 @@
package net.pokeranalytics.android.ui.modules.handhistory
import android.Manifest
import android.animation.ValueAnimator
import android.app.Activity
import android.app.AlertDialog
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Canvas
import android.os.Bundle
import android.os.Handler
import android.view.*
@ -701,8 +703,8 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDelegate, KeyboardL
builder.setTitle(R.string.export)
builder.setItems(
arrayOf<CharSequence>(
getString(R.string.text)
// getString(R.string.video),
getString(R.string.text),
getString(R.string.video)
// "GIF"
)
) { _, index ->
@ -710,7 +712,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDelegate, KeyboardL
// of the selected item
when (index) {
0 -> this.textExport()
1 -> this.videoExport()
1 -> this.videoExportAskForPermission()
2 -> this.gifExport()
}
}
@ -718,31 +720,36 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDelegate, KeyboardL
}
private fun videoExportAskForPermission() {
askForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, RequestCode.PERMISSION_WRITE_EXTERNAL_STORAGE.value) { granted ->
if (granted) {
videoExport()
}
}
}
private fun videoExport() {
val config = ReplayerAnimator(this.model.handHistory)
val animator = ReplayerAnimator(this.model.handHistory, true)
val square = 1024f
val width = 480
val height = 480
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val tc = TableDrawer(bitmap)
val width = square
val height = square
// draw initial table
// TableDrawer.initializeTable(config, tc, requireContext())
// TODO
animator.setDimension(width, height)
TableDrawer.configurePaints(requireContext(), animator)
val muxer = MMediaMuxer()
muxer.Init(requireActivity(), bitmap.width, bitmap.height, "hhVideo", "YES!")
muxer.Init(requireActivity(), width.toInt(), height.toInt(), "hhVideo", "YES!")
HandStep.createSteps(this.model.handHistory).forEach { step ->
animator.frames(requireContext()) { bitmap ->
step.frames(config, tc, requireContext()) {
try {
val byteArray = bitmap.toByteArray()
muxer.AddFrame(byteArray)
} catch (e: Exception) {
Timber.e("error = ${e.message}")
}
try {
val byteArray = bitmap.toByteArray()
muxer.AddFrame(byteArray)
} catch (e: Exception) {
Timber.e("error = ${e.message}")
}
}

@ -66,7 +66,7 @@ class ActionList(var listener: ActionListListener? = null) : ArrayList<ComputedA
position
)
this.add(ca)
Timber.d(">> CA: position:${ca.position}, ${ca.action.amount}, ${ca.stackBeforeActing}, ${ca.stackAfterActing}")
// Timber.d(">> CA: position:${ca.position}, ${ca.action.amount}, ${ca.stackBeforeActing}, ${ca.stackAfterActing}")
}
// Adds action

@ -1,5 +1,8 @@
package net.pokeranalytics.android.ui.modules.handhistory.replayer
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.RectF
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.handhistory.Street
@ -9,14 +12,14 @@ import net.pokeranalytics.android.ui.modules.handhistory.model.ComputedAction
import timber.log.Timber
import kotlin.math.max
class ReplayerAnimator(var handHistory: HandHistory) {
class ReplayerAnimator(var handHistory: HandHistory, var export: Boolean) {
// Steps & Frames
enum class FrameType {
STATE,
GATHER_ANIMATION,
DISTRIBUTION_ANIMATION
enum class FrameType(val visualOccurences: Int) {
STATE(20),
GATHER_ANIMATION(1),
DISTRIBUTION_ANIMATION(1)
}
/***
@ -422,13 +425,13 @@ class ReplayerAnimator(var handHistory: HandHistory) {
return computedAction
}
fun next() {
fun nextStep() {
if (this.steps.size > this.currentStepIndex + 1) {
this.currentStepIndex += 1
}
}
fun previous() {
fun previousStep() {
if (this.currentStepIndex > this.lastBlindIndex + 1) {
this.currentStepIndex -= 1
}
@ -496,6 +499,29 @@ class ReplayerAnimator(var handHistory: HandHistory) {
return false
}
fun frames(context: Context, frameHandler: (Bitmap) -> Unit) {
this.steps.forEach { step ->
while (this.shouldShowAdditionalFrame) {
val bitmap = Bitmap.createBitmap(this.width.toInt(), this.height.toInt(), Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
TableDrawer.drawTable(this, canvas, context)
(0 until this.frameType.visualOccurences).forEach { i ->
Timber.d(">>> step: $currentStepIndex, currentFrame: $currentFrame, vo = $i")
frameHandler(bitmap)
}
// bitmap.recycle()
frameDrawn()
}
nextStep()
}
}
/***
* Returns whether the replayer has finished showing steps & frames or not
*/

@ -79,7 +79,7 @@ class ReplayerFragment : RealmFragment() {
}
private fun loadHand(handHistory: HandHistory) {
val config = ReplayerAnimator(handHistory)
val config = ReplayerAnimator(handHistory, false)
this.replayer.animator = config
this.model.animator = config
}

@ -20,11 +20,11 @@ class ReplayerModel : ViewModel() {
private set
fun previousStep() {
this.animator?.previous()
this.animator?.previousStep()
}
fun nextStep() {
this.animator?.next()
this.animator?.nextStep()
}
val actionDelay: Long

@ -9,10 +9,10 @@ import android.media.MediaCodecInfo.CodecCapabilities
import android.os.Environment
import android.os.Handler
import android.util.Log
import net.pokeranalytics.android.util.extensions.dateTimeFileFormatted
import timber.log.Timber
import java.io.File
import java.io.IOException
import java.text.DateFormat
import java.util.*
@ -200,15 +200,14 @@ class MMediaMuxer {
it.start()
}
try {
val currentDateTimeString =
DateFormat.getDateTimeInstance().format(Date())
val formattedDate = Date().dateTimeFileFormatted
outputPath = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES),
"pixel.mp4"
"video_${formattedDate}.mp4"
).toString()
mediaMuxer = MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
} catch (ioe: IOException) {
Loge("MediaMuxer creation failed")
Loge("MediaMuxer creation failed: ${ioe.message}")
}
}
@ -279,7 +278,7 @@ class MMediaMuxer {
mediaMuxer!!.stop()
mediaMuxer!!.release()
mediaMuxer = null
Logd("RELEASE MUXER, path = ${outputPath}")
Logd("RELEASE MUXER, path = $outputPath")
}
}
@ -354,8 +353,8 @@ class MMediaMuxer {
private var _height = 512
private const val BIT_RATE = 800000
private const val INFLAME_INTERVAL = 1
private const val FRAME_RATE = 10
private const val DEBUG = false
private const val FRAME_RATE = 50
// private const val DEBUG = false
private const val TAG = "CODEC"
/**
* Returns the first codec capable of encoding the specified MIME type, or
@ -417,7 +416,7 @@ class MMediaMuxer {
}
private fun Logd(Mess: String) {
Timber.d("$Mess")
Timber.d(Mess)
// if (DEBUG) {
// Log.d(TAG, Mess)
// }

Loading…
Cancel
Save