Ver Fonte

Process and save image in paralle to speed up exporting

Wayne há 6 anos atrás
pai
commit
ac04250940

+ 60 - 29
src/main/java/com/bomostory/sceneeditmodule/SuperMovieMaker.kt

@@ -11,12 +11,14 @@ import com.bomostory.sceneeditmodule.basicdata.Scene
 import com.example.exportmedia.MediaHelper
 import com.example.exportmedia.data.AudioSource
 import com.example.exportmedia.vedio.MovieMaker
+import io.reactivex.Completable
 import io.reactivex.Observable
+import io.reactivex.schedulers.Schedulers
 import java.io.File
 import java.util.AbstractMap
+import java.util.concurrent.Semaphore
 import kotlin.collections.ArrayList
 import kotlin.collections.LinkedHashMap
-import kotlin.collections.List
 import kotlin.collections.set
 import kotlin.math.pow
 
@@ -35,35 +37,33 @@ class SuperMovieMaker {
             movieBuilder.audioSources = generateAudioSource(musics)
 
             val inputSceneStatus = LinkedHashMap<Int, Int>()
-            var sceneIndex = -1
-            var sceneRepeatCount = 0
-            var sceneCount = 0
-
-            var totalFrame = 0
-            scene?.record?.period?.let {
-                totalFrame = (it / ((1f / FPS) * 1000).toLong()).toInt()
-            }
-
-            generateMovieFilms(
-                    scene,
-                    scaleWidth,
-                    scaleHeight
-            )
-                    .subscribe {
-                        val msg = "progress ${sceneCount++}/$totalFrame"
-                        emitter.onNext("Compute image $msg")
-                        Log.d("Debug", msg)
-                        if (it.key == sceneIndex) {
-                            sceneRepeatCount++
-                        } else {
-                            sceneIndex = it.key
-                            sceneRepeatCount = 1
-                            movieBuilder.addImage(it.key, it.value).subscribe()
-                            emitter.onNext("Save image $msg")
+            val frameDataList = generateFrameDataList(scene)
+            var bitmapIndex = 0
+            val permitCount = frameDataList.size
+            val semaphore = Semaphore(permitCount)
+            var completeCount = 0
+            emitter.onNext("$completeCount/${frameDataList.size}")
+
+            var beginTime = System.currentTimeMillis()
+            frameDataList.forEach { frameData ->
+                val i = bitmapIndex++
+                inputSceneStatus[i] = frameData.repeat
+                semaphore.acquire()
+                Completable.create {
+                    val bitmap = drawScene(scene, frameData.x, scaleWidth, scaleHeight)
+                    movieBuilder.addImage(i, bitmap!!).blockingSubscribe()
+                    it.onComplete()
+                }
+                        .subscribeOn(Schedulers.computation())
+                        .subscribe {
+                            completeCount++
+                            emitter.onNext("$completeCount/${frameDataList.size}")
+                            semaphore.release()
                         }
-                        inputSceneStatus[sceneIndex] = sceneRepeatCount
-                    }
-
+            }
+            semaphore.acquire(permitCount)
+            var endTime = System.currentTimeMillis()
+            Log.d(this@SuperMovieMaker::class.java.simpleName, "draw + save duration = ${endTime - beginTime}")
             movieBuilder.inputFilePath = movieBuilder.addInputFile(inputSceneStatus).blockingFirst()
             emitter.onNext("Encoding video")
             movieBuilder.build().output(outputFile).blockingSubscribe()
@@ -83,6 +83,35 @@ class SuperMovieMaker {
         return audioSources
     }
 
+    fun generateFrameDataList(scene: Scene): List<FrameData> {
+        val frameDataList = ArrayList<FrameData>()
+        scene.record?.apply {
+            var x = 0
+            var trackPosition = -1
+
+            for (t in 0..period step ((1f / FPS) * 1000).toLong()) {
+                for (track in tracks) {
+                    if (t >= track.time && tracks.indexOf(track) > trackPosition) {
+                        x = track.positionX
+                        trackPosition = tracks.indexOf(track)
+                    }
+                }
+
+                if (frameDataList.isEmpty()) {
+                    frameDataList.add(FrameData(x, 1))
+                } else {
+                    val frameData = frameDataList.last()
+                    if (frameData.x == x) {
+                        frameData.repeat++
+                    } else {
+                        frameDataList.add(FrameData(x, 1))
+                    }
+                }
+            }
+        }
+        return frameDataList
+    }
+
     private fun generateMovieFilms(
             scene: Scene,
             scaleWidth: Int,
@@ -140,4 +169,6 @@ class SuperMovieMaker {
         }
         return sceneBitmap
     }
+
+    data class FrameData(var x: Int, var repeat: Int)
 }