Skip to main content
Language:

From Remote URL

VideoEditor SDK supports loading filters from a remote URL, this can be a resource hosted by a photo hosting provider or your servers. Although the editor supports adding assets with remote URLs, we highly recommend that you manage the download of remote resources yourself, since this gives you more control over the whole process.

Download filter#

For each remote resource, we create a File in the cache directory and download the remote resource. Since file handling and downloading are IO operations, we do this inside a coroutine using the IO dispatcher.

Create LutColorFilterAsset#

Here, we construct a LutColorFilterAsset object using the file downloaded above. Additionally, we also specify the horizontal and vertical tiles as well as the texture size.

Add filter to AssetConfig#

To use the filter, it must first be available in the SDK's backend. This is done by adding the filter to the AssetConfig.

Create filter group#

In cases where we want to simplify navigation and discovery, we can group sets of related filters that will appear in a single folder in the filter tool.

Create a FolderItem passing a unique identifier, a display name for the group and a thumbnail for the group folder.

Configure UiConfigFilter#

Here, we configure UiConfigFilter and add the custom FolderItem we created above to the filterList. Alternatively, we could have directly added the FilterItem to the filterList without creating a folder.

File:
class VideoAddFiltersFromRemoteURL(private val activity: AppCompatActivity) : Example(activity) {
// Although the editor supports adding assets with remote URLs, we highly recommend
// that you manage the download of remote resources yourself, since this
// gives you more control over the whole process.
override fun invoke() {
// Filenames of remote assets
val filterFilename = "custom_lut_invert.png"
val thumbnailFilename = "custom_filter_category.jpg"
// All available filenames of the assets
val assetFilenames = arrayOf(filterFilename, thumbnailFilename)
activity.lifecycleScope.launch {
showLoader(true)
val files = runCatching {
coroutineScope {
// Download each of the remote resources
assetFilenames.map {
async(Dispatchers.IO) {
// Create file in cache directory
val file = File(activity.cacheDir, it)
if (file.exists()) file.delete()
file.createNewFile()
// Save remote resource to file
URL("https://img.ly/static/example-assets/$it").openStream().use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
file
}
}.awaitAll() // Wait for all downloads to finish
}
}.getOrNull()
showLoader(false)
files?.let {
startEditor(it)
} ?: showMessage("Error downloading the file")
}
}
private fun startEditor(files: List<File>) {
// In this example, we do not need access to the Uri(s) after the editor is closed
// so we pass false in the constructor
val settingsList = VideoEditorSettingsList(false)
// Set the source as the Uri of the image to be loaded
.configure<LoadSettings> {
it.source = activity.resourceUri(R.raw.skater)
}
// Create a custom LUT filter using the downloaded file
val customLUTFilter = LutColorFilterAsset("custom_lut_filter", ImageSource.create(files[0]), 5, 5, 128)
// Add asset to AssetConfig
settingsList.config.addAsset(customLUTFilter)
// Create custom filters folder
val customFiltersFolder = FolderItem(
"custom_filter_category", "Custom", ImageSource.create(files[1]), listOf(
FilterItem("custom_lut_filter", "Invert")
)
)
settingsList.configure<UiConfigFilter> {
// Alternatively, we could have directly added FilterItem(s) here without creating a folder.
it.filterList.add(customFiltersFolder)
}
// Start the video editor using VideoEditorBuilder
// The result will be obtained in onActivityResult() corresponding to EDITOR_REQUEST_CODE
VideoEditorBuilder(activity)
.setSettingsList(settingsList)
.startActivityForResult(activity, EDITOR_REQUEST_CODE)
// Release the SettingsList once done
settingsList.release()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
intent ?: return
if (requestCode == EDITOR_REQUEST_CODE) {
// Wrap the intent into an EditorSDKResult
val result = EditorSDKResult(intent)
when (result.resultStatus) {
EditorSDKResult.Status.CANCELED -> showMessage("Editor cancelled")
EditorSDKResult.Status.EXPORT_DONE -> showMessage("Result saved at ${result.resultUri}")
else -> {
}
}
}
}
}