Skip to content

Commit

Permalink
Add version 2.8.0
Browse files Browse the repository at this point in the history
  • Loading branch information
leontobias committed Mar 28, 2023
1 parent 7db0bf6 commit bf15ec0
Show file tree
Hide file tree
Showing 13 changed files with 396 additions and 88 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## [2.8.0]

### Added

* [video_editor_sdk] Added `VideoEditorResult.segments`, `VideoEditorResult.videoSize`, and `VideoEditorResult.release()` which enable serialization of the individual video composition components if `VideoOptions.segments` is enabled.
* [video_editor_sdk] Added `FlutterVESDK.editorWillOpenClosure` and `FlutterVESDK.editorWillExportClosure` which allow further native configuration on Android.
* [photo_editor_sdk] Added `FlutterPESDK.editorWillOpenClosure` and `FlutterPESDK.editorWillExportClosure` which allow further native configuration on Android.

### Fixed

* [imgly_sdk] Fixed `TextOptions.canvasActions` would use `StickerCanvasAction` instead of `TextCanvasAction`.

## [2.7.1]

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ In order to run any samples or use any wrapper without a watermark,
you'll have to purchase a commercial PhotoEditor SDK or VideoEditor SDK
license. Visit https://img.ly for more details.

Copyright (c) 2014-2022, img.ly GmbH
Copyright (c) 2014-2023, img.ly GmbH
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Add the plugin package to the `pubspec.yaml` file in your project:

```yaml
dependencies:
video_editor_sdk: ^2.7.1
video_editor_sdk: ^2.8.0
```
Install the new dependency:
Expand Down Expand Up @@ -107,13 +107,13 @@ Run with --stacktrace option to get the stack trace. Run with --info or --debug
}
dependencies {
...
+ classpath 'ly.img.android.sdk:plugin:10.4.0'
+ classpath 'ly.img.android.sdk:plugin:10.4.1'
...
}
}
```

In order to update VideoEditor SDK for Android replace the version string `10.4.0` with a [newer release](https://github.com/imgly/pesdk-android-demo/releases).
In order to update VideoEditor SDK for Android replace the version string `10.4.1` with a [newer release](https://github.com/imgly/pesdk-android-demo/releases).

2. Still in the `android/build.gradle` file (**not** `android/app/build.gradle`), add these lines at the bottom:

Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ imglyConfig {
}
}

def MIN_LY_IMG_ANDROID_SDK_PLUGIN_VERSION = "10.4.0"
def MIN_LY_IMG_ANDROID_SDK_PLUGIN_VERSION = "10.4.1"

task checkVersion {
if (imglyConfig.convertToVersionNumber(imglyConfig.getVersion()) < imglyConfig.convertToVersionNumber(MIN_LY_IMG_ANDROID_SDK_PLUGIN_VERSION)) {
Expand Down
1 change: 1 addition & 0 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
android:exported="false"
android:enabled="false"
android:name="ly.img.android.IMGLYAutoInit" />
<activity android:name="FlutterVESDKActivity" />
</application>
</manifest>
162 changes: 142 additions & 20 deletions android/src/main/kotlin/ly/img/flutter/video_editor_sdk/FlutterVESDK.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.annotation.NonNull
import android.content.Intent
import android.net.Uri
import android.util.Log
import androidx.annotation.WorkerThread

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
Expand All @@ -15,13 +16,18 @@ import ly.img.android.AuthorizationException
import ly.img.android.IMGLY
import ly.img.android.VESDK
import ly.img.android.pesdk.VideoEditorSettingsList
import ly.img.android.pesdk.backend.decoder.VideoSource
import ly.img.android.pesdk.backend.model.state.LoadSettings
import ly.img.android.pesdk.kotlin_extension.continueWithExceptions
import ly.img.android.pesdk.utils.UriHelper
import ly.img.android.sdk.config.*
import ly.img.android.pesdk.backend.encoder.Encoder
import ly.img.android.pesdk.backend.model.EditorSDKResult
import ly.img.android.pesdk.backend.model.VideoPart
import ly.img.android.pesdk.backend.model.state.VideoCompositionSettings
import ly.img.android.pesdk.backend.model.state.manager.SettingsList
import ly.img.android.pesdk.backend.model.state.manager.StateHandler
import ly.img.android.pesdk.ui.activity.VideoEditorActivity
import ly.img.android.pesdk.utils.ThreadUtils
import ly.img.android.serializer._3.IMGLYFileWriter

Expand All @@ -37,8 +43,18 @@ class FlutterVESDK: FlutterIMGLY() {
companion object {
// This number must be unique. It is public to allow client code to change it if the same value is used elsewhere.
var EDITOR_RESULT_ID = 29064

/** A closure to modify a *VideoEditorSettingsList* before the editor is opened. */
var editorWillOpenClosure: ((settingsList: VideoEditorSettingsList) -> Unit)? = null

/** A closure allowing access to the *StateHandler* before the editor is exporting. */
var editorWillExportClosure: ((stateHandler: StateHandler) -> Unit)? = null
}

private var resolveManually: Boolean = false
private var currentEditorUID: String = UUID.randomUUID().toString()
private var settingsLists: MutableMap<String, SettingsList> = mutableMapOf()

override fun onAttachedToEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
super.onAttachedToEngine(binding)

Expand All @@ -65,6 +81,7 @@ class FlutterVESDK: FlutterIMGLY() {

val video = call.argument<MutableMap<String, Any>>("video")
if (video != null) {
val videoSegments = video["segments"] as ArrayList<*>?
val videosList = video["videos"] as ArrayList<String>?
val videoSource = video["video"] as String?
val size = video["size"] as? MutableMap<String, Double>
Expand All @@ -73,9 +90,11 @@ class FlutterVESDK: FlutterIMGLY() {

if (videoSource != null) {
this.present(videoSource.let { EmbeddedAsset(it).resolvedURI }, config, serialization)
} else {
} else if (videosList != null) {
val videos = videosList?.mapNotNull { EmbeddedAsset(it).resolvedURI }
this.present(videos, config, serialization, size)
} else {
this.present(videoSegments, config, serialization, size)
}
} else {
result.error("VE.SDK", "The video must not be null", null)
Expand All @@ -84,6 +103,14 @@ class FlutterVESDK: FlutterIMGLY() {
val license = call.argument<String>("license")
this.result = result
this.resolveLicense(license)
} else if (call.method == "release") {
val identifier = call.argument<String>("identifier")
if (identifier == null) {
result.error("VE.SDK", "The identifier must not be null", null)
} else {
this.result = result
this.releaseTemporaryData(identifier)
}
} else {
result.notImplemented()
}
Expand All @@ -98,7 +125,12 @@ class FlutterVESDK: FlutterIMGLY() {
*/
override fun present(asset: String, config: HashMap<String, Any>?, serialization: String?) {
val configuration = ConfigLoader.readFrom(config ?: mapOf())
val settingsList = VideoEditorSettingsList(configuration.export?.serialization?.enabled == true)
val serializationEnabled = configuration.export?.serialization?.enabled == true
val exportVideoSegments = configuration.export?.video?.segments == true
val createTemporaryFiles = serializationEnabled || exportVideoSegments
resolveManually = exportVideoSegments

val settingsList = VideoEditorSettingsList(createTemporaryFiles)
configuration.applyOn(settingsList)
currentConfig = configuration

Expand All @@ -108,41 +140,46 @@ class FlutterVESDK: FlutterIMGLY() {
}
}

applyTheme(settingsList, configuration.theme)

editorWillOpenClosure?.invoke(settingsList)
readSerialisation(settingsList, serialization, false)
startEditor(settingsList, EDITOR_RESULT_ID)
applyTheme(settingsList, configuration.theme)
startEditor(settingsList, EDITOR_RESULT_ID, FlutterVESDKActivity::class.java)
}

/**
* Configures and presents the editor.
*
* @param videos The video sources as *List<String>* which should be loaded into the editor.
* @param videos The video sources as *List<*>* which should be loaded into the editor.
* @param config The *Configuration* to configure the editor with as if any.
* @param serialization The serialization to load into the editor if any.
*/
private fun present(videos: List<String>?, config: HashMap<String, Any>?, serialization: String?, size: Map<String, Any>?) {
private fun present(videos: List<*>?, config: HashMap<String, Any>?, serialization: String?, size: Map<String, Any>?) {
val videoArray = deserializeVideoParts(videos)
var source = resolveSize(size)

val configuration = ConfigLoader.readFrom(config ?: mapOf())
val settingsList = VideoEditorSettingsList(configuration.export?.serialization?.enabled == true)
val serializationEnabled = configuration.export?.serialization?.enabled == true
val exportVideoSegments = configuration.export?.video?.segments == true
val createTemporaryFiles = serializationEnabled || exportVideoSegments
resolveManually = exportVideoSegments

val settingsList = VideoEditorSettingsList(createTemporaryFiles)
configuration.applyOn(settingsList)
currentConfig = configuration

var source = resolveSize(size)
if (videos != null && videos.count() > 0) {
if (videoArray.isNotEmpty()) {
if (source == null) {
if (size != null) {
result?.error("VE.SDK", "Invalid video size: width and height must be greater than zero.", null)
this.result = null
return
}
val video = videos.first()
source = retrieveURI(video)
val video = videoArray.first()
source = video.videoSource.getSourceAsUri()
}

settingsList.configure<VideoCompositionSettings> { loadSettings ->
videos.forEach {
val resolvedSource = retrieveURI(it)
loadSettings.addCompositionPart(VideoCompositionSettings.VideoPart(resolvedSource))
videoArray.forEach {
loadSettings.addCompositionPart(it)
}
}
} else {
Expand All @@ -157,10 +194,20 @@ class FlutterVESDK: FlutterIMGLY() {
it.source = source
}

editorWillOpenClosure?.invoke(settingsList)
readSerialisation(settingsList, serialization, false)
applyTheme(settingsList, configuration.theme)
startEditor(settingsList, EDITOR_RESULT_ID, FlutterVESDKActivity::class.java)
}

readSerialisation(settingsList, serialization, false)
startEditor(settingsList, EDITOR_RESULT_ID)
private fun releaseTemporaryData(identifier: String) {
val settingsList = settingsLists[identifier]
if (settingsList != null) {
settingsList.release()
settingsLists.remove(identifier)
}
this.result?.success(null)
this.result = null
}

private fun retrieveURI(source: String) : Uri {
Expand All @@ -185,6 +232,50 @@ class FlutterVESDK: FlutterIMGLY() {
return LoadSettings.compositionSource(width.toInt(), height.toInt(), 60)
}

private fun serializeVideoSegments(settingsList: SettingsList): List<*> {
val compositionParts = mutableListOf<MutableMap<String, Any?>>()
settingsList[VideoCompositionSettings::class].videos.forEach {
val source = it.videoSource.getSourceAsUri().toString()
val trimStart = it.trimStartInNano / 1000000000.0f
val trimEnd = it.trimEndInNano / 1000000000.0f

val videoPart = mutableMapOf<String, Any?>(
"videoUri" to source,
"startTime" to trimStart.toDouble(),
"endTime" to trimEnd.toDouble()
)
compositionParts.add(videoPart)
}
return compositionParts
}

private fun deserializeVideoParts(videos: List<*>?) : List<VideoPart> {
val parts = emptyList<VideoPart>().toMutableList()

videos?.forEach {
if (it is String) {
val videoPart = VideoPart(retrieveURI(EmbeddedAsset(it).resolvedURI))
parts.add(videoPart)
} else if (it is Map<*, *>) {
val uri = it["videoUri"] as String?
val trimStart = it["startTime"] as Double?
val trimEnd = it["endTime"] as Double?

if (uri != null) {
val videoPart = VideoPart(retrieveURI(EmbeddedAsset(uri).resolvedURI))
if (trimStart != null) {
videoPart.trimStartInNanoseconds = (trimStart * 1000000000.0f).toLong()
}
if (trimEnd != null) {
videoPart.trimEndInNanoseconds = (trimEnd * 1000000000.0f).toLong()
}
parts.add(videoPart)
}
}
}
return parts
}

/**
* Unlocks the SDK with a stringified license.
*
Expand Down Expand Up @@ -222,8 +313,9 @@ class FlutterVESDK: FlutterIMGLY() {
val sourceUri = intentData.sourceUri

var serialization: Any? = null
val settingsList = intentData.settingsList

if (serializationConfig?.enabled == true) {
val settingsList = intentData.settingsList
skipIfNotExists {
settingsList.let { settingsList ->
serialization = when (serializationConfig.exportType) {
Expand All @@ -241,23 +333,53 @@ class FlutterVESDK: FlutterIMGLY() {
}
}
}
settingsList.release()
} ?: run {
Log.e("IMG.LY SDK", "You need to include 'backend:serializer' Module, to use serialisation!")
}
}

var segments: List<*>? = null
val canvasSize = sourceUri?.let { VideoSource.create(it).fetchFormatInfo()?.size }
val sizeMap = mutableMapOf<String, Any>()
if (canvasSize != null && canvasSize.height >= 0 && canvasSize.width >= 0) {
sizeMap["height"] = canvasSize.height.toDouble()
sizeMap["width"] = canvasSize.width.toDouble()
}

if (resolveManually) {
settingsLists[currentEditorUID] = settingsList
segments = serializeVideoSegments(settingsList)
}

val map = mutableMapOf<String, Any?>()
map["video"] = resultUri.toString()
map["hasChanges"] = (sourceUri?.path != resultUri?.path)
map["serialization"] = serialization
map["segments"] = segments
map["identifier"] = currentEditorUID
map["videoSize"] = sizeMap

currentActivity?.runOnUiThread {
this.result?.success(map)
this.result = null
}
if (!resolveManually) {
settingsList.release()
}
resolveManually = false
}
return true
}
return false
}
}

/** A *VideoEditorActivity* used for the native interfaces. */
class FlutterVESDKActivity: VideoEditorActivity() {
@WorkerThread
override fun onExportStart(stateHandler: StateHandler) {
FlutterVESDK.editorWillExportClosure?.invoke(stateHandler)

super.onExportStart(stateHandler)
}
}
2 changes: 1 addition & 1 deletion example/android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
buildscript {
ext.kotlin_version = '1.5.32'
ext.vesdk_version = '10.4.0'
ext.vesdk_version = '10.4.1'

repositories {
google()
Expand Down
Loading

0 comments on commit bf15ec0

Please sign in to comment.