# Banuba Video and Photo Editor SDKs Documentation > Docs provides full information about Banuba Video and Photo Editor SDKs, integration and customization guides. This file contains all documentation content in a single document following the llmstxt.org standard. ## Customization Options Video Editor SDK on Android Banuba Video Editor SDK has built in UI/UX experience and provides a number of customizations you can use to meet your requirements. **AVAILABLE** :white_check_mark: Use your branded icons, colors, and text styles. [See details](ve-faq.md) :white_check_mark: Localize and change text resources. Default locale is :us: :white_check_mark: Make content you want i.e. a number of video with different resolutions and durations, an audio file. :white_check_mark: Masks and filters order. [See details](ve-faq.md) **NOT AVAILABLE** :x: Change layout or order of screens after entry point Feel free to [request](https://www.banuba.com/support) custom UI/UX development. --- ## AI Clipping on Android The [AI Clipping](https://www.banuba.com/ai-sdk) feature automates the video creation process by leveraging the power of artificial intelligence. The neural network transforms raw input into ready-to-post videos with various transitions, effects, and a precise music match. :::important The ```AI Clipping``` is based on the [Banuba Face AR SDK](https://www.banuba.com/facear-sdk/face-filters) product. Since this feature uses additional services, it is disabled by default. Please contact Banuba representatives to know more about using this feature. ::: Here is how users can interact with it: 1. User selects clips and music. People can choose their desired clips and accompanying music within the app. 2. AI trims the videos. The AI algorithm intelligently trims the selected clips to match the tempo and rhythm of the chosen track. 3. AI adds various effects. AI Clipping enhances the content by adding a variety of effects to create visually stunning content. 4. User exports, edits, or regenerates the clip. Upon completion, users have the flexibility to export the video as is, make further edits, or regenerate the clip for a fresh perspective. Regardless of the user’s editing skills, with the help of AI Clipping, everyone can get a stunning video within seconds.   ## Supported Music Providers - [Banuba Music](guide_audio_content.md#connect-banuba-music) - [Soundstripe](guide_audio_content.md#connect-soundstripe) ## Integration ### Setup configuration Add ```Banuba Face AR SDK``` module by following the [Face AR instruction](guide_far_arcloud.md#integrate-face-ar). Set up ```AiClippingConfig```, ```AutoCutTrackLoader``` and ```ContentFeatureProvider``` dependencies in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L51) :::important Contact Banuba representative to get trial keys for ```audioDataUrl``` and ```audioTracksUrl``` ::: ### Config with Banuba Music provider ```kotlin factory { AiClippingConfig( audioDataUrl = "https://d27n29bgbvbeer.cloudfront.net/index-staging.zip", audioTracksUrl = "" ) } factory { AiClippingBanubaMusicTrackLoader(contentProvider = get()) } factory>( named("recommendedSoundsMusicTrackProvider") ) { AiClippingRecommendedSoundProvider() } ``` ### Config with Soundstripe provider ```kotlin factory { AiClippingConfig( audioDataUrl = "...", audioTracksUrl = "..." ) } factory { AiClippingSoundstripeTrackLoader(soundstripeApi = get()) } factory>( named("recommendedSoundsMusicTrackProvider") ) { AiClippingRecommendedSoundProvider() } ``` ### Launch AI Clipping :::info Video creation with AI Clipping is available on Gallery screen by default. ::: For better experience we added new entry point to `VideoCreationActivity` for opening AI Clipping as a separate mode. In this scenario the user starts from the gallery screen and is taken to AI Clipping screen after selecting media. Use the `Intent` to start new mode. ```kotlin val intent = VideoCreationActivity.startFromAiClipping(Context) ``` --- ## Closed Captions on Android Closed captions(CC) are a textual representation of the audio within a media file. :::important The Close Captions feature is disabled by default. Please contact Banuba representatives to know more about using this feature. ::: Over 80% of videos played on mobile devices don’t have sound turned on. This means many forms of content (e.g. skits, monologues, educational clips, etc.) will be skipped if there are no subtitles. But making captions by hand is tedious. AI-generated subtitles solve this issue, as they are created and placed automatically. The users can then edit the text as well as change its style and color.       [AWS Transcribe service](https://docs.aws.amazon.com/transcribe/) is used to generate captions. ## Supported languages - Arabic - English - Mandarin - Spanish - Portuguese ## Integration Create ```Bundle``` with Closed Captions configuration and pass ```extras``` to any Video Editor start method. ### Closed Captions V2 (Recommended) :::important Request API V2 key from Banuba representatives. ::: ```kotlin val extras = bundleOf( CaptionsApiService.ARG_API_KEY_V2 to "...", ) ``` ### Closed Captions V1 :::important Request keys from Banuba representatives. ::: ```kotlin val extras = bundleOf( CaptionsApiService.ARG_CAPTIONS_UPLOAD_URL to "...", CaptionsApiService.ARG_CAPTIONS_TRANSCRIBE_URL to "...", CaptionsApiService.ARG_API_KEY to "...", ) ``` Use ```extras``` in any start method of the Video Editor SDK ```kotlin VideoCreationActivity.startFromCamera( context = applicationContext, pictureInPictureConfig = PipConfig( video = pipVideo, openPipSettings = editorSettingsProvider.openPipSettings ), audioTrackData = initialTrackData, extras = extras ) ``` --- ## Dependencies and Licenses on Android Lists used dependencies and licenses in the SDK. ## Dependencies | Name | Version | | --------- |---------| | androidx.activity:activity-ktx | 1.10.1 | | androidx.annotation:annotation | 1.9.1 | | androidx.appcompat:appcompat | 1.7.0 | | androidx.constraintlayout:constraintlayout | 2.1.4 | | androidx.core:core-ktx | 1.15.0 | | androidx.exifinterface:exifinterface | 1.4.0 | | androidx.fragment:fragment-ktx | 1.8.6 | | androidx.lifecycle:lifecycle-livedata-ktx | 2.8.7 | | androidx.lifecycle:lifecycle-runtime-ktx | 2.8.7 | | androidx.lifecycle:lifecycle-service | 2.8.7 | | androidx.lifecycle:lifecycle-viewmodel-ktx | 2.8.7 | | androidx.localbroadcastmanager:localbroadcastmanager | 1.0.0 | | androidx.recyclerview:recyclerview | 1.4.0 | | com.airbnb.android:lottie | 3.5.0 | | com.github.bumptech.glide:glide | 4.15.0 | | androidx.media3:media3-exoplayer | 1.6.0 | | com.google.android.material:material | 1.12.0 | | com.squareup.moshi:moshi-kotlin | 1.15.2 | | com.squareup.moshi:moshi-kotlin-codegen | 1.15.2 | | com.squareup.okhttp3:logging-interceptor | 4.12.0 | | com.squareup.okhttp3:okhttp | 4.12.0 | | com.squareup.retrofit2:converter-moshi | 2.11.0 | | com.squareup.retrofit2:retrofit | 2.11.0 | | io.insert-koin:koin-android | 3.5.6 | | org.apache.commons:commons-math3 | 3.6.1 | | org.jetbrains.kotlin:kotlin-stdlib-jdk7 | 2.1.0 | | org.jetbrains.kotlin:kotlin-reflect | 2.1.0 | | org.jetbrains.kotlinx:kotlinx-coroutines-android | 1.10.1 | | org.jetbrains.kotlinx:kotlinx-coroutines-core | 1.10.1 | ## 3rd party licenses ### **GNU Lesser General Public Licence version 3.0 or later** This library is free software and is governed by GNU Lesser General Public License, version 3.0, available at https://www.gnu.org/licenses/lgpl-3.0.en.html. | Name | Link | Copyright info | | --- | --- | --- | | FFmpeg | [https://github.com/tanersener/mobile-ffmpeg](https://github.com/tanersener/mobile-ffmpeg) | Copyright (c) ffmpeg Authors | ## **MIT License** "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." | Name | Link | Copyright info | | --- | --- | --- | | json | [https://github.com/nlohmann/json](https://github.com/nlohmann/json) | Copyright (c) 2013-2019 Niels Lohmann | | Android-gif-drawable | [https://github.com/koral--/android-gif-drawable](https://github.com/koral--/android-gif-drawable) | Copyright (c) 2013 - present Karol Wrótniak, Droids on Roids LLC | ## **Apache License 2.0** "Licensed under the Apache License, Version 2.0 (the ""License""); you may not use this file except in compliance with the License. You may obtain a copy of the License at: [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an ""AS IS"" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License." | Name | Link | Copyright info | |-------------------| --- | --- | | Media 3 ExoPlayer | [https://developer.android.com/media/media3/exoplayer](https://developer.android.com/media/media3/exoplayer) | | | OkHttp | [https://github.com/square/okhttp](https://github.com/square/okhttp) | Copyright 2019 Square, Inc. | | Retrofit | [https://github.com/square/retrofit](https://github.com/square/retrofit) | Copyright 2013 Square, Inc. | | Okio | [https://github.com/square/okio](https://github.com/square/okio) | Copyright 2013 Square, Inc. | | Koin | [https://github.com/InsertKoinIO/koin](https://github.com/InsertKoinIO/koin) | Copyright 2017-2021 Arnaud GIULIANI, Laurent BARESSE | | Moshi | [https://github.com/square/moshi](https://github.com/square/moshi) | Copyright 2015 Square, Inc. | | Lottie | [https://github.com/airbnb/lottie-android](https://github.com/airbnb/lottie-android) | Copyright 2018 Airbnb, Inc. | ## **3-clause BSD License** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. " | Name | Link | Copyright info | | --- | --- | --- | | Libyuv | [https://chromium.googlesource.com/libyuv/libyuv](https://chromium.googlesource.com/libyuv/libyuv) | Copyright 2011 The LibYuv Project Authors | | Glide | [https://github.com/bumptech/glide](https://github.com/bumptech/glide) | Copyright 2014 Google, Inc. All rights reserved. | ## Face AR SDK [View](https://docs.banuba.com/face-ar-sdk/overview/3rd_licenses) third party libraries for Banuba Face AR SDK --- ## Use of FFmpeg Banuba Video Editor SDK uses FFmpeg version ```5.3.0 ``` ## Guidelines to use FFmpeg dependency in your app: Add Banuba FFmpeg dependency from gradle file. ```groovy implementation "com.banuba.sdk:ffmpeg:5.3.0" ``` Add the following code in your Activity to check whether everything is correct: ```kotlin com.banuba.sdk.ve.processing.FFmpeg(context = this).execute(emptyArray()).run { waitFor() Log.d("FFmpeg", errorStream.reader().readText()) } ``` The output should contain information about version of FFmpeg libraries. We recommend using our FFMpeg functionality, as it offers a very wide range of tools. --- ## Audio content on Android Guide to integrating and customizing audio providers in Video Editor SDK. ## Overview Audio content is a key part of making awesome video. Video Editor SDK can play, trim, merge and add audio content to a video. :::info 1. Banuba does not deliver audio content for Video Editor SDK. 2. Video Editor can apply audio file stored on the device. The SDK is not responsible for downloading audio content except [Soundstripe](https://www.soundstripe.com/) and [Banuba Music](#connect-banuba-music) 3. Video Editor SDK supports only one music provider per launch. ::: There are 2 approaches of using audio content: 1. ```AudioBrowser``` - specific module and a set of screens that includes built in support of browsing and applying audio content within video editor. The user does not leave the sdk while using audio. 2. ```External API``` - the client implements specific API for managing audio content. The user leaves the SDK and is taken to an app screen when audio is requested. ## Audio Browser Audio Browser is a specific Android module that allows to browse, play and apply audio content within video editor. It supports 3 sources for audio content: 1. ```Banuba Music``` - includes build in integration with Banuba Music, 2. ```Soundstripe``` - includes built in integration with [Soundstripe](https://www.soundstripe.com/) API, 3. ```My Library``` - includes audio content available on the user's device. Add the dependency ```kotlin implementation "com.banuba.sdk:ve-audio-browser-sdk:${version}" ``` to your [gradle](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/build.gradle#L77) file and specify ```AudioBrowserKoinModule``` Koin module in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L57) ```diff startKoin { ... modules( // highlight-add-next-line + AudioBrowserKoinModule().module, VideoEditorKoinModule().module ) } ``` to integrate ```AudioBrowser```. ## Connect Banuba Music Over 35 GB of royalty-free tracks available from within the Video Editor SDK. Your users could check them out through an inbuilt music browser and legally include them in their content. :::info The feature is not activated by default. Please contact Banuba representatives to know more about using this feature. :::   Use ```BanubaMusicProvider``` implementation in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L64) ```kotlin import com.banuba.sdk.audiobrowser.api.BanubaMusicProvider single>(named("musicTrackProvider")){ BanubaMusicProvider() } ``` ## Connect Soundstripe [Soundstripe](https://www.soundstripe.com/) is a service for providing the best audio tracks for creating video content. Your users will be able to add audio tracks while recording or editing video content. :::info The feature is not activated by default. Please contact Banuba representatives to know more about using this feature. :::     Use ```SoundstripeProvider``` implementation in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L64) ```kotlin single>(named("musicTrackProvider")){ SoundstripeProvider() } ``` ## Connect My Library ```My Library``` is a default implementation in ```AudioBrowser``` . It allows the user to apply audio that is available on a device. Use ```AudioBrowserMusicProvider``` implementation in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L75) to enable ```My Library```. ```kotlin single>(named("musicTrackProvider")) { AudioBrowserMusicProvider() } ``` ## Integrate Client Audio provider on Android Video Editor includes special API for integrating your custom audio content provider and applying this content in video editor. The user will be taken to your app specific screen when audio is requested on video editor screen i.e. camera or editor. Next, once the user picks audio content on your app screen you need to follow API and return the user to video editor. Any audio file should stored on the device before applying. Below is a guide of using API to provide your audio to video editor. First, create new Activity ```CustomAudioContentActivity``` that will handle API and create new method to start it from video editor. This Activity you can use to implement any API for downloading audio content and showing your beautiful UI to your users. ```kotlin class CustomAudioContentActivity : AppCompatActivity() { ... companion object { fun buildPickMusicResourceIntent( context: Context, extras: Bundle ) = Intent(context, AwesomeAudioContentActivity::class.java).apply { putExtras(extras) } } } ``` where ```extras``` includes a data that can be used in the Activity. 1. ```ProvideTrackContract.EXTRA_LAST_PROVIDED_TRACK``` of TrackData. Can be null. ```null``` is used to dismiss audio. 2. ```ProvideTrackContract.EXTRA_TRACK_TYPE``` of TrackType. Next, create ```CustomActivityMusicProvider``` and implement ```ContentFeatureProvider```. ```kotlin class CustomActivityMusicProvider : ContentFeatureProvider { private var activityResultLauncher: ActivityResultLauncher? = null private val activityResultCallback: (TrackData?) -> Unit = { activityResultCallbackInternal(it) } private var activityResultCallbackInternal: (TrackData?) -> Unit = {} override fun init(hostFragment: WeakReference) { activityResultLauncher = hostFragment.get()?.registerForActivityResult( ProvideTrackContract(), activityResultCallback ) } override fun requestContent( context: Context, extras: Bundle ): ContentFeatureProvider.Result = ContentFeatureProvider.Result.RequestUi( intent = CustomAudioContentActivity.buildPickMusicResourceIntent( context, extras ) ) override fun handleResult( hostFragment: WeakReference, intent: Intent, block: (TrackData?) -> Unit ) { activityResultCallbackInternal = block activityResultLauncher?.launch(intent) } } ``` And set ```CustomActivityMusicProvider``` to [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L75) ```kotlin single>(named("musicTrackProvider"), override = true) { CustomActivityMusicProvider() } ``` Please keep in mind that only one instance of ```musicTrackProvider``` can exist either your custom of```External API``` or ```Audio Browser```. Finally, pass audio content to apply audio in video editor. Instance of ```TrackData``` is used for passing in ```Intent``` to video editor. The audio should be stored on the device. ```kotlin val trackData = TrackData( UUID.randomUUID(), "My awesome track", audioTrackUri, // Uri of the audio track on local storage // file:///data/user/0//files//awesome.wav "Awesome Artist" ) ``` To pass ```TrackData``` to video editor your need to use ```setResult``` with ```Intent``` and finish current Activity. ```kotlin val trackToApply: TrackData = ... val resultIntent = Intent().apply { putExtra(ProvideTrackContract.EXTRA_RESULT_TRACK_DATA, trackToApply) } setResult(Activity.RESULT_OK, resultIntent) finish() ``` To dismiss previously selected audio track you can pass ```null``` for ```TrackData```. ## Resources The following string resources are used in ```AudioBrowser```. | ResourceId | Value | | ------------- | :----------- | | apply_track | Use | | remove_track| Stop\nusing | | track_loading_failed | Sorry, audio content is temporarily unavailable | | track_search_cancel | Cancel | | audio_browser_title_library | My library | | audio_browser_title_category | Music | | audio_browser_title_empty_category | Music | | audio_browser_load_more | Show more | | audio_browser_error_tracks_not_found | No tracks found | | audio_browser_error_categories_not_found | No categories found | | audio_browser_error_empty_library | No tracks yet | | audio_browser_error_license_not_active | The license is not active | | audio_browser_error_license_expired | The license expired | | audio_browser_error_license_access | Access denied, check license access type | | audio_browser_error_license_api_version | Access denied, check license API version | | audio_browser_hint_search_categories | Search by categories | | audio_browser_hint_search_sub_categories | Search by groups | | audio_browser_hint_search_tracks | Search by tracks | | audio_browser_error_dialog_title | Oops, something went wrong… | | audio_browser_error_dialog_description | Please, try again later. | | audio_browser_error_dialog_retry | Retry | | audio_browser_error_dialog_close | Close | | permission_library_description_message | Allow to access to your storage to select an audio tracks from your device. | | audio_browser_connection_error_title | No internet connection | | audio_browser_connection_error_message | Please, check your connection and try again. | | audio_browser_connection_error_btn | Retry | | audio_browser_connection_error_toast | No internet connection | | action_add_music_track | Tracks | | action_add_voice_recording | Record | | action_effects | Effects | | action_edit | Edit | | action_delete | Delete | | edit_track_volume_title | Volume | | edit_track_volume_percent | %1$d%% | | edit_track_audio_duration | Audio duration | | edit_track_duration_error | Audio should be longer than %1$.1f sec | | error_voice_recording_start | Error on voice recording start | | error_invalid_duration_voice_recording | Min voice recording duration - %1$.1f sec | | error_invalid_duration_music_track | Min music track duration - %1$.1f sec | | error_voice_recording_delete_file | Internal error when try to delete voice recording file | | error_track_limit | Max available tracks - %1$d | | error_no_space | No space | --- ## Camera screen on Android Guide to modifying camera UI elements and screen configuration. ## Change icons You can use your app specific icons in Video Editor SDK. Add icon files to Android ```drawable``` folder with predefined names. :::info We strongly recommend using vector assets (.svg files). :::   Below is a list of icons. Each icon has a few states - on, off and modes. Specific file name should be assigned to each state. The filename on the right. Example, ```ic_camera_switch_on_new.xml``` file is used in the SDK to denote the state when a flipper is on. 1. Flip 1. **on** - ```ic_camera_switch_on_new``` 2. **off** - ```ic_camera_switch_off_new``` 2. Flash 1. **on** - ```ic_flashlight_on_new``` 2. **off** - ```ic_flashlight_off_new``` 3. Speed 1. **x0.5** - ```ic_recording_speed_x0_5_new``` 2. **x1** - ```ic_recording_speed_x1_new``` 3. **x2** - ```ic_recording_speed_x2_new``` 4. **x3** - ```ic_recording_speed_x3_new``` 5. **x0.5 selected** - ```ic_recording_speed_x0_5_selected_new``` 6. **x1 selected** - ```ic_recording_speed_x1_selected_new``` 7. **x2 selected** - ```ic_recording_speed_x2_selected_new``` 8. **x3 selected** - ```ic_recording_speed_x3_selected_new``` 4. Mic 1. **on** - ```ic_mute_mic_on_new``` 2. **off** - ```ic_mute_mic_off_new``` 5. Beauty 1. **on** - ```ic_beauty_on_new``` 2. **off** - ```ic_beauty_off_new``` 6. Filter 1. **on** - ```ic_color_on_new``` 2. **off** - ```ic_color_off_new``` 7. PIP 1. **on** - ```ic_pip_on_new``` 2. **off** - ```ic_pip_off_new``` 8. Mask 1. **on** - ```ic_mask_on_new``` 2. **off** - ```ic_mask_off_new``` 9. Music 1. **on** - ```ic_music_on_white``` 2. **off** - ```ic_music_on_white``` 10. Timer 1. ```ic_timer_new``` --- ## Camera Layouts on Android Camera Layouts lets you replace the background of your camera view in real time. Users can choose from three options: - **Blur** — Softens the background to keep the subject in focus. - **Custom color** — Replaces the background with any solid color. - **Media** — Uses an image or a video file as the background. This feature replaces the previous Green Screen and Weatherman features. Both are now included under Camera Layouts.     :::important The feature requires the Face AR product with Background Segmentation feature enabled. Without Background Segmentation, this feature will not appear or function. Contact Banuba representatives to enable it ::: --- ## Cover image on Android Cover image screen allows users to pick any frame of video as image or choose an image from gallery. ```CoverProvider``` supports 2 modes - ```EXTENDED``` - enables the screen - ```NONE``` - disables the screen. The user is taken to export screen. ```EXTENDED``` is **default** mode in the SDK. You can change the mode in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L75) ``` kotlin single(override = true) { CoverProvider.EXTENDED } ``` ## Resources You can override the following string resources in your app. | ResourceId | Value | |--------------| :----------- | | cover_image_text | Choose cover | | cover_progress_text | Please, wait | | err_cover_image | Failed to create cover image | --- ## Drafts screen on Android Guide to integrating and customizing drafts screen on Video Editor SDK. ## Configuration Drafts are enabled by default, asks the user to save a draft before leave any VideoEditor screen. If you need to change drafts configuration you should add the code below in the [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L60): ```kotlin override val draftConfig: BeanDefinition = factory(override = true) { DraftConfig.ENABLED_ASK_TO_SAVE } ``` You can choose one of these options: 1. `ENABLED_ASK_TO_SAVE` - drafts enabled, asks the user to save a draft 2. `ENABLED_ASK_IF_SAVE_NOT_EXPORT` - drafts enabled, asks the user to save a draft without export 3. `ENABLED_SAVE_BY_DEFAULT` - drafts enabled, saved by default without asking the user 4. `DISABLED` - disabled drafts ## Draft Helper ```DraftsHelper``` interface is used for managing drafts. ``` kotlin interface DraftsHelper { val allDrafts: StateFlow> fun delete(draft: Draft) fun deleteAll() fun openDraft(draft: Draft): Intent fun openLastDraft(): Intent } ``` To get the instance of ```DraftsHelper``` use the following in your Fragment or Activity. ``` kotlin val draftsHelper: DraftsHelper by inject() ``` ### Used string resources | ResourceId | Value | |:----------:|:-----:| |drafts_title|Drafts| |drafts_empty_description|No Drafts| |drafts_options_edit|Edit| |drafts_options_delete|Delete| |editor_trim_video|Adjust Clips| |editor_discard_changes|Discard changes| |editor_update_draft|Update draft| --- ## Editor screen on Android Guide to integrating and customizing Editor screen. ## Change icons You can use your app specific icons in Video Editor SDK. Add icon files to Android ```drawable``` folder with predefined names. :::info We strongly recommend using vector assets (.svg files). :::   Below is a list of icons. Each icon has a few states - on, off, disabled. Specific file name should be assigned to each state. The filename on the right. Example, ```ic_gif_on.xml``` file is used in the SDK to denote the state when a sticker is added to the video. 1. Stickers 1. **on** - ```ic_gif_on``` 2. **off** - ```ic_gif_off``` 2. Text 1. **on** - ```ic_text_effect_on``` 2. **off** - ```ic_text_effect_off``` 3. Captions 1. **on** - ```ic_captions_on``` 2. **off** - ```ic_captions_off``` 3. **disabled** - ```ic_captions_disabled``` 4. Effects 1. **on** - ```ic_visual_effect_on``` 2. **off** - ```ic_visual_effect_off``` 5. Masks 1. **on** - ```ic_mask_on``` 2. **off** - ```ic_mask_off``` 6. Music 1. **on** - ```ic_music_on``` 2. **off** - ```ic_music_off``` 7. Time 1. **on** - ```ic_time_effect_on``` 2. **off** - ```ic_time_effect_off``` 8. Filters 1. **on** - ```ic_lut_on``` 2. **off** - ```ic_lut_off``` 9. Blur 1. **on** - ```ic_blur_on``` 2. **off** - ```ic_blur_off``` 10. AI Clipping 1. **on** - ```ic_autocut_on``` 2. **off** - ```ic_autocut_off``` --- ## NEW Editor screen on Android Guide to integrating and customizing New Editor screen. ## Overview With the new interface, better controls, and additional quality of life improvements, making stunning videos is easier and more fun than ever. Design and user experience principles are constantly evolving. To keep up with the latest developments and best practices, our team has completely redesigned the Video Editor SDK to be as convenient and enjoyable as possible.       ## Integration Create ```Bundle``` with Editor UI V2 configuration and pass ```extras``` to any Video Editor start method. ```kotlin val extras = bundleOf( "EXTRA_USE_EDITOR_V2" to true ) ``` ```kotlin VideoCreationActivity.startFromCamera( context = applicationContext, pictureInPictureConfig = PipConfig( video = pipVideo, openPipSettings = false ), audioTrackData = initialTrackData, extras = extras ) ``` --- ## Export media on Android Video Editor SDK allows to export a number of media files i.e. video and audio with various resolutions and other configurations. Video is exported as ```.mp4``` file. :::info Export is a very heavy computational task that takes time and the user has to wait. Execution time depends on 1. Video duration - the longer video the longer execution time. 2. Number of video sources - the many sources the longer execution time. 3. Number of effects and their usage in video - the more effects and their usage the longer execution time. 4. Number of exported video - the more video and audio you want to export the longer execution time. 5. Device hardware - the most powerful devices can execute export much quicker and with higher resolution. ::: Export supports 2 modes: - ```Foreground``` - the user has to wait on progress screen until processing is done. **Default** - ```Background``` - the user can close the editor and open an app specific screen. A certain notification is sent when processing is done. ```ForegroundExportFlowManager``` and ```BackgroundExportFlowManager``` are corresponding implementations. Here is a screen that is shown in ```Foreground``` mode.

screen export media

## Video quality Video Editor supports video codec options: 1. ```HEVC``` - H265 codec. **Default** 2. ```AVC_PROFILES``` - H264 codec with profiles 3. ```BASELINE``` - H264 codec without profiles The following table presents list of video resolution and bitrate values for codec ```H264(AVC_PROFILES)```. | 240p(240x426) | 360p(360x640) | 480p(480x854) | QHD540(540x960) | HD(720x1280) | FHD(1080x1920) | QHD(1440x2560) | UHD(2160x3840) | |---------------|------------|---------------|-----------------|--------------|----------------|----------------|----------------| | 1000 kb/s | 1200 kb/s | 2000 kb/s | 2400 kb/s | 3600 kb/s | 5800 kb/s | 10000 kb/s | 20000 kb/s | :::info Video Editor includes built-in feature for detecting device performance capabilities and finding ```auto``` video quality for exported video. ::: ## Export storage All exported media files are stored in ```export``` directory on the device storage. You can specify another directory by overriding ```exportDir``` dependency in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L51). Default implementation is ```kotlin single(named("exportDir")) { get().getExternalFilesDir("")?.toUri() ?.buildUpon() ?.appendPath("export") ?.build() ?: throw NullPointerException("exportDir cannot be null!") } ``` ## Implement export flow :::info Default implementation exports single video file with auto quality(based on device hardware capabilities). ::: You can create your own export flow to meet your requirements. First, specify list of media files to export. Create new class ```CustomExportParamsProvider``` and implement ```ExportParamsProvider```. Method ```provideExportParams``` returns ```List``` which is a list of media files to export. The following implementation exports single video with ```HD``` and ```auto``` quality ```kotlin class CustomExportParamsProvider( private val exportDir: Uri, private val watermarkBuilder: WatermarkBuilder ) : ExportParamsProvider { override fun provideExportParams( effects: Effects, videoRangeList: VideoRangeList, musicEffects: List, videoVolume: Float ): List { val exportSessionDir = exportDir.toFile().apply { deleteRecursively() mkdirs() } // Video is in HD resolution val exportVideoHD = ExportParams.Builder(VideoResolution.Exact.HD) .effects(effects) .fileName("export_video_hd") .videoRangeList(videoRangeList) .destDir(exportSessionDir) .musicEffects(musicEffects) .volumeVideo(videoVolume) .build() // Video is in auto resolution val exportVideoAuto = ExportParams.Builder() .effects(effects) .fileName("export_video_auto") .videoRangeList(videoRangeList) .destDir(exportSessionDir) .musicEffects(musicEffects) .volumeVideo(videoVolume) .build() return listOf(exportVideoHD, exportVideoAuto) } } ``` Use constructor ```ExportParams.Builder()``` or specific method ```videoResolution()```to set up custom video quality. ```diff val exportVideoHD = // highlight-add-next-line + ExportParams.Builder(VideoResolution.Exact.HD) .effects(effects) .fileName("export_video_hd") .videoRangeList(videoRangeList) .destDir(exportSessionDir) .musicEffects(musicEffects) .volumeVideo(videoVolume) .build() ``` :::warning Please keep in mind that low level devices might not be able to export video with high quality. Our recommendations 1. Use ```HD``` or ```VGA480``` resolutions with codec ```H264(AVC_PROFILES)``` 2. Do not specify certain video quality. In this case ```auto``` quality will be used. ::: Next, specify ```CustomExportParamsProvider``` implementation in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L51) ```kotlin factory { CustomExportParamsProvider( exportDir = get(named("exportDir")), watermarkBuilder = get() ) } ``` Finally, use the most suitable export mode for your application in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L51). ```ForegroundExportFlowManager``` is used by default. ## Use AVC codec The SDK prefers ```H265(HEVC)``` codec by default for exporting video file. You can specify ```H264(AVC_PROFILES)``` by setting ```false``` to ```useHevcIfPossible```. :::info ```H264(AVC_PROFILES)``` is recommended for low level devices ::: ```diff ExportParams.Builder(VideoResolution.Exact.HD) ... // highlight-add-next-line + useHevcIfPossible(false) .build(), ``` ## Add watermark Watermark is not added to exported video by default. Create new class ```CustomWatermarkProvider``` and implement ```WatermarkProvider``` to use your custom watermark image. ```kotlin private class CustomWatermarkProvider(private val context: Context) : WatermarkProvider { override fun getWatermarkBitmap(): Bitmap? { val watermarkDrawableRes = ... // R.drawable. val watermark = BitmapFactory.decodeResource( context.resources, watermarkDrawableRes ) return watermark } } ``` and specify it in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L51) ```kotlin factory { CustomWatermarkProvider() } ``` Use extension method ```Effects.withWatermark``` for adding a watermark to ```ExportParams.Builder```. ```diff ExportParams.Builder(VideoResolution.Exact.HD) // highlight-add-next-line + .effects(effects.withWatermark(watermarkBuilder, WatermarkAlignment.BottomRight(marginRightPx = 16.toPx))) ... .build(), ``` where ```WatermarkBuilder``` provides watermark drawable and ```alignment``` is used where to locate drawable ```kotlin WatermarkAlignment { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT } ``` ## Export soundtrack track You can export video and audio soundtrack file separately. For example, ```Kotlin val extraSoundtrackUri = Uri.parse(exportSessionDir.toString()).buildUpon() .appendPath("exported_soundtrack.${MediaFileNameHelper.DEFAULT_SOUND_FORMAT}") .build() val exportVideoAndSoundtrack = ExportParams.Builder(VideoResolution.Exact.HD) .fileName("export_extra_soundtrack") .videoRangeList(videoRangeList) .destDir(exportSessionDir) .musicEffects(musicEffects) .extraAudioFile(extraSoundtrackUri) .volumeVideo(videoVolume) .build() ``` and add ```exportVideoAndSoundtrack``` to the list of exported video files in your custom ```ExportParamsProvider```. ## Handle export result The result is returned to your controller in [registerForActivityResult](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/MainActivity.kt#L27) method as an instance of ```ExportResult```. ```kotlin private val createVideoRequest = registerForActivityResult(CustomExportResultVideoContract()) { exportResult -> exportResult?.let { if (exportResult is ExportResult.Success) { // Get uri of first exported video file val videoUri = exportResult.videoList.getOrNull(0) ... } } } ``` ```ExportResult``` class ```kotlin sealed class ExportResult { object Inactive : ExportResult() object Stopped : ExportResult() data class Progress( val preview: Uri ) : ExportResult() @Parcelize data class Success( val videoList: List, val preview: Uri, val metaUri: Uri, val additionalExportData: Parcelable? = null ) : ExportResult(), Parcelable @Parcelize data class Error(val type: ExportError) : ExportResult(), Parcelable } ``` Instance of ```ExportResult.Success``` is returned with all export data when export finishes successfully. ```ExportResult.Error``` is returned when an error is occurred while exporting media content. ## Export in background If you want to export media in the background and avoid showing progress screen to your user you can use ```BackgroundExportFlowManager``` implementation in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L51) and provide your custom implementations. ```kotlin single { BackgroundExportFlowManager( exportDataProvider = get(), exportSessionHelper = get(), exportNotificationManager = get(), exportDir = get(named("exportDir")), shouldClearSessionOnFinish = true, publishManager = get(), errorParser = get(), exportBundleProvider = get(), eventConverter = get() ) } ``` Next, specify Android ```CustomActivity``` that opens after export in ```AndroidManifest.xml``` file and set special ``` ``` . Please use ```applicationId``` as a part of intent action name to make it unique among other possible intent actions ```kotlin ``` Create new class ```CustomExportResultHandler``` and implement ```ExportResultHandler``` that will start your Activity mentioned above. ```kotlin class CustomExportResultHandler : ExportResultHandler { override fun doAction(activity: AppCompatActivity, result: ExportResult.Success?) { val intent = Intent("${activity.packageName}.ShowExportResult").apply { result?.let { putExtra(EXTRA_EXPORTED_SUCCESS, it) } addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) } activity.startActivity(intent) } } ``` **Note**: action that is passed into ```Intent``` constructor **must be the same** as the action name from activity intent filter above. Next, add ```ExportFlowManager``` dependency using Koin and observe for ```ExportResult``` in ```CustomActivity``` ```kotlin class CustomActivity: AppCompatActivity() { private val exportFlowManager: ExportFlowManager by inject() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) exportFlowManager.resultData.nonNull().observe(this) { exportResult -> //... } } } ``` **Optional**. Provide ```ExportNotificationManager``` to manage notifications about exporting process state. There are 3 options: 1. Remove notifications all notifications ```kotlin class EmptyExportNotificationManger() : ExportNotificationManager { fun showExportStartedNotification(){} fun showSuccessfulExportNotification(result: ExportResult.Success){} fun showFailedExportExportNotification(){} } ``` and provide this implementation in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L75): ```kotlin single { EmptyExportNotificationManger() } ``` 2. Customize default implementation You can override the following android resources: - R.string.export.notification_started - for message about started export - R.string.export_notification_success - for message about succeeded export - R.string.export_notification_fail - for message about failed export - R.drawable.ic_export_notification - for notification icon in system bar 3. Provide custom implementation of ```ExportNotificationManager``` in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L75) ```kotlin single { CustomExportNotificationManger() } ``` ## Export GIF preview Video Editor allows to export preview of a video as a GIF file. Use ```GifMaker.Params``` in your ```CustomExportParamsProvider``` to create params for exporting GIF preview ```kotlin data class Params( val destFile: File, val sourceVideoRangeMs: LongRange = 0..1000L, val fps: Int = 15, val width: Int = 240, val useDithering: Boolean = true, val reverse: Boolean = true ) ``` where - `destFile` - where to store the file - `sourceVideoRangeMs` - is a range of exported video that will be used to create gif image - `fps` - frames per second within gif image - `width` - width of gif image in pixels - `useDithering` - flag that apply or remove dithering effect (in simple words make an image of better quality) - `reverse` - flag to reverse playback inside gif Use ```interactivePreview``` method in ```ExportParams.Builder``` to enable exporting GIF ```diff ExportParams.Builder(sizeProvider.videoResolution) .effects(effects) .fileName("export_video") .videoRangeList(videoRangeList) .destDir(exportSessionDir) .musicEffects(musicEffects) .extraAudioFile(extraSoundtrackUri) .volumeVideo(videoVolume) // highlight-add-next-line + .interactivePreview(gifPreviewParams) .build() ``` ## Get audio used in export You can get all audio used in exported video when export finished successfully. ```ExportBundleHelper.getExportedMusicEffect``` requires ```additionalExportData``` value of ```ExportResult.Success```. The result is ```List``` where ```MusicEffectExportData``` is ```kotlin @Parcelize data class MusicEffectExportData( val title: String, val type: MusicEffectType, val uri: Uri ) : Parcelable ``` `MusicEffectType` contains next values: 1. `TRACK` - audio tracks that were added on the `Editor` screen 2. `VOICE` - voice record track that was added on the `Editor` screen 3. `CAMERA_TRACK` - audio track that was added on the `Camera` screen ## Export metadata analytics Video Editor generates simple metadata analytics while exporting media content that you can use to analyze what media content your users make. Metadata is a JSON string and can be returned from ```ExportResult.Success``` in this way ```kotlin //"exportResult" is an instance of ExportResult.Success object val outputBundle = exportResult.additionalExportData.getBundle(ExportBundleProvider.Keys.EXTRA_EXPORT_OUTPUT_INFO) val analytics = outputBundle?.getString(ExportBundleProvider.Keys.EXTRA_EXPORT_ANALYTICS_DATA) ``` ```ExportBundleProvider.Keys``` includes all constants you can use for parsing. Sample ```JSON { "export_success": true, // defines if the export finished succesffully "aspect_ratio": "original", // aspect ration used in exported video "video_resolutions": ["1080x1920"], // list of video resolutions used in export "camera_effects": [], // list of effects of features used on camera screen while recording video "ppt_effects": { "visual": 2, // num of visual effects i.e. Glitch, VHS used in exported video "speed": 1, // num of speed effects used in exported video "mask": 6, // num of AR masks used in exported video "color": 3, // num of color effects used in exported video "text": 1, // num of text effects used in exported video "sticker": 1, // num of sticker effects used in exported video "blur": 1 // num of blur effects used in exported video }, "sources": { "camera": 0, // num of video sources recorded on camera screen(not PIP) "gallery": 1, // num of video sources selected in the gallery "pip": 0, // num of video recorded with PIP "slideshow": 0, // num of video exported as slideshow "audio": 0 // num of audi tracks }, "export_duration": 12.645, // export processing duration "video_duration": 20.11, // exported video duration "video_count": 1, // num of exported video files "os_version": "11", // OS version "sdk_version": "1.26.6" // VE SDK version } ``` --- ## Face AR and AR Cloud products on Android [Banuba Face AR SDK](https://www.banuba.com/facear-sdk/face-filters) product is used on camera and editor screens for applying various AR effects while making video content. ## Overview Any Face AR effect is a folder that includes a number of files required for Face AR SDK to play this effect. :::tip Make sure ```preview.png``` file is included in effect folder. You can use this file as a preview for AR effect. ::: ## Integrate Face AR :::info ```Banuba Face AR SDK``` integration is included in the [Github sample](https://github.com/Banuba/ve-sdk-android-integration-sample). ::: Follow next steps to integrate ```Banuba Face AR SDK``` into your project. First, add Gradle ```com.banuba.sdk:effect-player-adapter``` dependency in [app gradle file](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/build.gradle#L74). ```diff def banubaSdkVersion = '1.52.0' ... // highlight-add-next-line + implementation "com.banuba.sdk:effect-player-adapter:${banubaSdkVersion}" ... ``` Add ```BanubaEffectPlayerKoinModule().module``` in the [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L40) ```diff startKoin { androidContext(this@IntegrationApp) modules( ... // highlight-add-next-line + BanubaEffectPlayerKoinModule().module ) } ``` ## Add and Manage effects There are 3 options for adding and managing AR effects: 1. Store all effects in [assets/bnb-resources/effects](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/assets/bnb-resources/effects) folder in the app. 2. Store color effects in [assets/bnb-resources/luts](https://github.com/Banuba/ve-sdk-android-integration-sample/tree/main/app/src/main/assets/bnb-resources/luts) folder in the app. 3. Use [AR Cloud](https://www.banuba.com/faq/what-is-ar-cloud) for storing effects on a server. :::tip You can use both options i.e. store just a few AR effects in ```assets``` and 100 or more AR effects on ```AR Cloud```. ::: ## Integrate AR Cloud ```AR Cloud``` is a cloud solution for storing Banuba Face AR effects on the server and used by Face AR and Video Editor products. Any AR effect downloaded from ```AR Cloud``` is cached on the user's device. Follow next steps to integrate ```AR Cloud``` into your project. First, add Gradle ```com.banuba.sdk:ar-cloud``` dependency in [app gradle file](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/build.gradle). ```diff def banubaSdkVersion = '1.52.0' ... // highlight-add-next-line + implementation "com.banuba.sdk:ar-cloud:${banubaSdkVersion}" ... ``` Next, add ```ArCloudKoinModule``` module to [Koin modules](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L67). ```diff startKoin { ... modules( VeSdkKoinModule().module, ... // highlight-add-next-line + ArCloudKoinModule().module, ... ) } ``` Next, override ```ArEffectsRepositoryProvider``` in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L91). ```kotlin single(createdAtStart = true) { ArEffectsRepositoryProvider( arEffectsRepository = get(named("backendArEffectsRepository")), ioDispatcher = get(named("ioDispatcher")) ) } ``` ## Change order effects By default, all AR effects are listed in alphabetical order. AR effects from ```assets``` are listed in order. Create new class ```CustomMaskOrderProvider``` and implement ```OrderProvider``` to provide custom order. ```kotlin class CustomMaskOrderProvider : OrderProvider { override fun provide(): List = listOf("Background", "HeadphoneMusic") } ``` :::info These are names of specific directories in ```assets/bnb-resources/effects``` or on ```AR Cloud```. ::: Next, use ```CustomMaskOrderProvider``` in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L75) ```kotlin single(named("maskOrderProvider")) { CustomMaskOrderProvider() } ``` ## Disable Face AR SDK Video Editor SDK can be used without Face AR SDK. Remove ```BanubaEffectPlayerKoinModule().module``` from [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L62) ```diff startKoin { androidContext(this@IntegrationApp) modules( ... // highlight-remove-next-line - BanubaEffectPlayerKoinModule().module ) } ``` and remove Gradle dependency ```com.banuba.sdk:effect-player-adapter``` ```diff ... // highlight-remove-next-line - implementation "com.banuba.sdk:effect-player-adapter:${banubaSdkVersion}" ... ``` --- ## Drawing on Android Lets your users draw freely on screen. It is a convenient tool for highlighting important objects in the video or spicing up the frame with funny doodles or stylish art. There are 5 line variants to choose from for more self-expression opportunities. :::important The Drawing feature is disabled by default. Please contact Banuba representatives to know more about using this feature. :::       --- ## Gallery screen on Android Video Editor SDK includes built in gallery functionality where the user can pick any video or image and use it while making video. :::info Gallery is integrated by default. ::: ## Integration The following guide will help you to integrate gallery to your project if it was not added before. Add module ```com.banuba.sdk:ve-gallery-sdk:1.52.0``` to [gradle](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/build.gradle#L73) file and specify ```GalleryKoinModule``` module in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L39) ```diff startKoin { androidContext(this@IntegrationApp) modules( ... // highlight-add-next-line + GalleryKoinModule().module ) } ``` ## Customizations You can control options ```Videos``` and ```Photos``` by overriding instance of ```EditorConfig``` in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L51) . ```diff single { EditorConfig( // highlight-add-next-line + gallerySupportsVideo = ..., // true - show Videos, false - hide. Defaul - true // highlight-add-next-line + gallerySupportsImage = ..., // true - show Photos, false - hide. Default - true ) } ``` ## Implement custom gallery Video editor allows to replace default gallery with your custom. Please follow implementation guide. First, create ```CustomMediaContentProvider``` class that implements ```ContentFeatureProvider, Fragment>```. This class describes a contract between Video Editor and specific Fragment from your project for gallery. ```kotlin class CustomMediaContentProvider : ContentFeatureProvider, Fragment> { private var activityResultLauncher: ActivityResultLauncher? = null private val activityResultCallback: (List?) -> Unit = { activityResultCallbackInternal(it) } private var activityResultCallbackInternal: (List?) -> Unit = {} override fun init(hostComponent: WeakReference) { activityResultLauncher = hostComponent.get()?.registerForActivityResult( ProvideMediaContentContract(), activityResultCallback ) } override fun requestContent( context: Context, extras: Bundle ): ContentFeatureProvider.Result> = ContentFeatureProvider.Result.RequestUi( intent = SelectExternalContentActivity.newGetMediaIntent(context).apply { putExtras(extras) } ) override fun handleResult( hostComponent: WeakReference, intent: Intent, block: (List?) -> Unit ) { activityResultCallbackInternal = block activityResultLauncher?.launch(intent) } } ``` Method `init` is invoked in Video Editor to register `onActivityResult` callback and receive media content. `com.banuba.sdk.core.domain.ProvideMediaContentContract` class is used to manage data bundle that is passed between video editor and your custom media provider implementation. Method `requestContent` is used to create `Intent` for starting your custom Activity with gallery. `extras` argument contains metadata for media content selection and should be passed into your custom media provider. `handleResult` method connects `onActivityResult` callback within Video Editor with the media content provided by `CustomGalleryActivity`. Next, obtain media request params in your `CustomGalleryActivity.onCreate()` ```kotlin override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) intent.extras?.let { extras -> val params = ProvideMediaContentContract.obtainParams(extras) ... } ``` `Params` object contains data about request from video editor ```kotlin data class Params( val mode: OpenGalleryMode, val types: List, val maxCount: Int, val minCount: Int, val supportedFormats: List ) ``` `mode` - is a type of request (NORMAL, FEATURE_BACKGROUND, ADD_TO_TRIMMER) `types` - list of requested media types (Video, Image) `supportedFormats` - list of media file extensions that are supported by SDK Deliver media data from `CustomGalleryActivity` to Video Editor SDK ```kotlin val resultIntent = Intent().apply { putParcelableArrayListExtra( ProvideMediaContentContract.EXTRA_MEDIA_CONTENT_RESULT, ArrayList(selectedMedia) ) } setResult(Activity.RESULT_OK, resultIntent) ``` `selectedMedia` is a list of media Uris with **content://** scheme. Finally, provide `CustomMediaContentProvider` in `VideoEditorModule.kt` Koin module. ```kotlin factory, Fragment>>(named("mediaDataProvider"), override = true) { (external: Boolean?) -> CustomMediaContentProvider() } ``` and remove module `GalleryKoinModule` from the list of modules. ```diff startKoin { androidContext(applicationContext) allowOverride(true) modules( ... // highlight-remove-next-line - GalleryKoinModule().module, ... ) } ``` --- ## Open Photo Editor SDK from Camera screen on Android This guide demonstrates how to open [Photo Editor SDK](https://www.banuba.com/photo-editor-sdk) just after taking a photo on Video Editor Camera screen. All recorded video or taken images on Camera screen can be handled using ```MediaNavigationProcessor```. Provide custom implementation of ```MediaNavigationProcessor``` in Koin module to override flow. ``` diff class SampleIntegrationKoinModule { val module = module { ... // highlight-add-next-line + single { object : MediaNavigationProcessor { override fun process(activity: Activity, mediaList: List): Boolean { // Filter media resources to find the target image for Photo Editor SDK val pngs = mediaList.filter { it.path?.contains(".png") ?: false } return if (pngs.isEmpty()) { true } else { // Create ExportResult and close Video Editor SDK. (activity as? VideoCreationActivity)?.closeWithResult( ExportResult.Success( emptyList(), pngs.first(), Uri.EMPTY, Bundle() ) ) false } } } } } ``` Handle received ```ExportResult``` in your ```registerForActivityResult``` or ```Activity.onActivityForResult``` method. ```diff private val createVideoRequest = registerForActivityResult(CustomExportResultVideoContract()) { exportResult -> exportResult?.let { if (exportResult is ExportResult.Success) { // Use exported preview file to open Photo Editor SDK // highlight-add-next-line photoEditorExportResult.launch( PhotoCreationActivity.startFromEditor( applicationContext, imageUri = exportResult.preview ) ) ... } } } private val photoEditorExportResult = registerForActivityResult(PhotoExportResultContract()) { uri -> // Handle exported image result } ``` --- ## Share video screen on Android Share video screen allows users to easily share an exported video using popular social media services and OS specific components. :::info This is an optional screen that you can add to your video editing flow. ::: ## Integration Create new layout ```activity_video_sharing.xml``` file in ```res/layout``` folder. This layout is required for integrating ```VideoSharingFragment``` from the SDK. ``` xml ``` Next, create new ```VideoSharingActivity``` that will handle social media keys and start video sharing screen. ``` kotlin class VideoSharingActivity : AppCompatActivity(R.layout.activity_video_sharing) { companion object { // Set up your Facebook app id const val FACEBOOK_APP_ID = "" } private val exportResult by lazy(LazyThreadSafetyMode.NONE) { intent?.getParcelableExtra(EXTRA_EXPORTED_SUCCESS) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val videoSharingFragment = VideoSharingFragment.newInstance( exportResult = exportResult, fbAppId = FACEBOOK_APP_ID ) supportFragmentManager.addFragment( videoSharingFragment, VideoSharingFragment.TAG, R.id.fragmentContainer, false ) } override fun onDestroy() { super.onDestroy() // SampleApp is an implementation available in main Video Editor Sample. // Release video editor dependencies when the user leaves this creen (application as? SampleApp)?.releaseVideoEditor() } } ``` and specify ```VideoSharingActivity``` in ```AndroidManifest.xml``` file. ``` xml ``` Finally, start ```VideoSharingActivity``` to open video sharing screen. ``` kotlin val intent = Intent(getString(com.banuba.sdk.export.R.string.export_action_name, packageName)).apply { putExtra(EXTRA_EXPORTED_SUCCESS, exportResult) } startActivity(intent) ``` --- ## Stickers on Android Guide to using stickers in Video Editor SDK on Android. ## Giphy Video Editor SDK has built in integration with [Giphy service](https://developers.giphy.com/docs/api/) for loading stickers. ```GIPHY``` doesn't charge for their content. The one thing they do require is attribution. Also, there is no commercial aspect to the current version of the product (no advertisements, etc.). Any sticker effect is a GIF file. To use stickers in your project you need to request personal [Giphy API key](https://support.giphy.com/hc/en-us/articles/360020283431-Request-A-GIPHY-API-Key). Override instance of ```GifPickerConfigurations``` and set GIPHY API key to ```giphyApiKey``` in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L53). ``` diff factory { GifPickerConfigurations( // highlight-add-next-line + giphyApiKey = .... ) } ``` Stickers will appear in the container on editor screen once ```giphyApiKey``` is set. --- ## Video recording integration guide on Android Guide to modifying video recording feature in Video Editor SDK. ## Quality details Subsequent table describes video quality details used for video recording in various resolutions. | Recording speed | 360p(360 x 640) | 480p(480 x 854) | HD(720 x 1280) | FHD(1080 x 1920) | | --------------- | --------------- | --------------- | -------------- | ---------------- | | 1x(Default) | 1200 | 2000 | 4000 | 6400 | | 0.5x | 900 | 1500 | 3000 | 4800 | | 2x | 1800 | 3000 | 6000 | 9600 | | 3x | 2400 | 4000 | 8000 | 12800 | ## Customize configurations ```CameraConfig``` is a main class used to customize features, behavior and user experience for video recording on camera screen i.e. set min/max recording duration, flashlight, etc. Video editor includes default implementation but you can provide your own implementation to meet your requirements in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt). For example, to sets max video recording duration to 30 seconds. ```kotlin single(override = true) { CameraConfig(maxRecordedTotalVideoDurationMs = 30_000) } ``` | Property | Values | Description | | ------------- |:--------------------------------------------------------------------------------------------:| :------------- | | minRecordedTotalVideoDurationMs | Number > 0; Default ```3000``` | minimum video recording duration *in milliseconds* required to proceed and open video editing screen (i.e. 3000 for 3 seconds) | maxRecordedTotalVideoDurationMs | Number > 0; Default ```120000``` | maximum video recording duration *in milliseconds* available to record | minRecordedChunkVideoDurationMs | Number > 1000; Default ```1000``` | minimum video recording duration *in milliseconds* that is allowed to record on camera | takePhotoOnTap | true/false; Default ```false``` | defines if it is available to take a photo on the camera screen by tap. ```true``` photo is taken by tap and video is recording by long press. | supportsMultiRecords | true/false; Default ```true``` | defines if the use can record multiple video subsequently. ```false``` when the first video recording is done the editing screen will be opened | supportsFlashlight | true/false; Default ```true``` | enables flashlight icon on the camera screen and possibility to take a photo with flashlight | supportsSpeedRecording | true/false; Default ```true``` | enables speed recording icon on the camera screen and possibility to select recording speed | supportsExternalMusic | true/false; Default ```true``` | enables the music icon on the camera screen and possibility to add music track playing over the video recording | supportsMuteMic | true/false; Default ```true``` | enables mute microphone icon on the camera screen and possibility to record video without capturing sound | switchFacingOnDoubleTap | true/false; Default ```true``` | ```true``` allows to switch between front and back camera by double tap | isStartFrontFacingFirst | true/false; Default ```true``` | ```true``` means that ```front``` camera facing is used on the first launch of the camera screen, ```false``` means that ```back``` camera facing is used on the first launch of the camera screen | isSaveLastCameraFacing | true/false; Default ```true``` | defines if the camera facing (```back``` or ```front```) is saved and restored | cameraFpsMode | CameraFpsMode enum values; Default ```CameraFpsMode.FIXED``` | ```CameraFpsMode.FIXED``` means that video recording quality can be degraded to maintain 30 FPS while applying "heavy" Face AR effects (*This behavior is recommended* and allows to reach seamless usage on wide range of devices). ```CameraFpsMode.ADAPTIVE``` means that FPS can be reduced in order to maintain video quality(not recommended). | showCameraInfoAndPerformance | true/false; Default ```false``` | enables debug views for showing camera system details such as current FPS, Iso etc. | supportsSwitchFacing | true/false; Default ```true``` | defines if camera facing switching is available. | supportsAudioRateEqualsVideoSpeed | true/false; Default ```false``` | determines if the audio playback speed is equal to the video recording speed. | supportsGallery | true/false; Default ```true``` | defines if there is an icon on the camera screen at the bottom-right to pick a content from gallery. | videoDurations | List<Long>; Default ```listOf(maxRecordedTotalVideoDurationMs, 60_000L, 30_000L, 15_000L)``` | defines the list of durations available to record. The user can see the option on the camera screen and pick new option. For example, ```60000L``` means that the user can record a number of video with total duration no more than 60 seconds. | supportsVideoDurationSwitcher | true/false; Default ```true``` | defines if video recording time interval swithced is enabled ## Configure microphone state Use ```CameraMuteMicConfig``` if you want to customize default state of microphone on the camera screen. Here is default implementation in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt) ```kotlin factory { CameraMuteMicConfig( // If mic should be muted when open camera screen in normal mode muteInNormalMode = false, // If mic should be muted when open camera screen in picture in picture mode muteInPipMode = true, // If mic should be muted when open camera screen with passed audio track muteWithAudioTrack = true ) } ``` ## Configure recording modes Camera screen includes 3 modes for recording content implemented as ```RecordMode``` - ```Photo``` - ```Video``` - ```Photo``` and ```Video``` - default value Implement ```CameraConfig``` in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt) to customize mode that meets your requirements. Default implementation is ```kotlin single{ CameraConfig( recordingModes = listOf(RecordMode.Video, RecordMode.Story) ) } ``` :::danger ```availableModes``` must not be empty, otherwise a crash will happen. ::: ## Picture in picture Picture in Picture or ```PIP``` is video editing technique that lets you overlay two videos in the same video. The multi-layer editing effect is perfect for reaction videos, slideshows, product demos, and more. This feature is similar to TikTok duet feature.

Screenshot 

:::info The feature is disabled by default and can be enabled if the license supports it. Please ask Banuba business representatives to include the feature in your license. ::: The subsequent guide explains how to start and customize ```PIP```. First, pass ```pictureInPictureConfig``` in [VideoCreationActivity.startFromCamera](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/MainActivity.kt#L179-L194) method ```kotlin val localVideoUri = ... VideoCreationActivity.startFromCamera( context = this, // set PiP video configuration pictureInPictureConfig = PipConfig( video = localVideoUri, openPipSettings = false // if you want to open pip settings at startup ) ) ``` ```PIP``` includes 4 modes that you can use. - ```Floating``` - ```TopBottom``` - ```React``` - ```LeftRight``` Implement ```PipLayoutProvider``` in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt) to customize the order of modes and other capabilities. ```kotlin single { object : PipLayoutProvider { override fun provide( insetsOffset: Int, screenSize: Size ): List { val context = androidContext() return listOf( EditorPipLayoutSettings.Floating( context = context, physicalScreenSize = screenSize, topOffsetPx = context.dimen(R.dimen.pip_floating_top_offset) + insetsOffset ), EditorPipLayoutSettings.TopBottom(), EditorPipLayoutSettings.React( context = context, physicalScreenSize = screenSize, topOffsetPx = context.dimen(R.dimen.pip_react_top_offset) + insetsOffset ), EditorPipLayoutSettings.LeftRight() ) } } } ``` Please do not forget to update [CameraMuteMicConfig](#configure-microphone-state) implementation if you want to change use of microphone in ```PIP```. You can even customize camera align for each mode and exclude actions for some modes: ```diff ... return listOf( EditorPipLayoutSettings.Floating( ..., excludeActions = listOf( EditorPipLayoutAction.SwitchVertical, EditorPipLayoutAction.Square, EditorPipLayoutAction.Round ), // highlight-add-next-line + isCameraAlignTop = false ), EditorPipLayoutSettings.TopBottom( excludeActions = listOf( EditorPipLayoutAction.SwitchVertical, EditorPipLayoutAction.Original, EditorPipLayoutAction.Centered ), // highlight-add-next-line + isCameraAlignTop = false ), EditorPipLayoutSettings.React( ..., excludeActions = listOf( EditorPipLayoutAction.SwitchVertical, EditorPipLayoutAction.Square, EditorPipLayoutAction.Round, EditorPipLayoutAction.Centered, EditorPipLayoutAction.Original ), isCameraMain = false ), EditorPipLayoutSettings.LeftRight( excludeActions = listOf( EditorPipLayoutAction.SwitchHorizontal, EditorPipLayoutAction.Original, EditorPipLayoutAction.Centered ), // highlight-add-next-line + isCameraAlignLeft = false ) ) ``` --- ## Install Photo Editor on Android Guide to installing Photo Editor SDK on Android. SDK modules are stored on GitHub Packages. ## Add repositories Open your project [gradle](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/build.gradle#L21) file and add repositories to ```allprojects``` section. ```groovy allprojects { repositories { maven { name = "nexus" url = uri("https://nexus.banuba.net/repository/maven-releases") } } } ``` ## Add dependencies Specify dependencies in the app [gradle](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/build.gradle#L83) file. ```groovy def banubaPESdkVersion = '1.3.8' implementation "com.banuba.sdk:pe-sdk:${banubaPESdkVersion}" def banubaSdkVersion = '1.52.0' implementation "com.banuba.sdk:core-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:core-ui-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:ve-gallery-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:effect-player-adapter:${banubaSdkVersion}" ``` Add ```kotlin-parcelize``` plugin into plugins section of the [gradle](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/build.gradle#L63) file. ```groovy plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-parcelize' } ``` --- ## Integration Video Editor on Android ## Installation Add the Banuba repository to your project using **either** Groovy **or** Kotlin DSL: **Groovy** (in project's [build.gradle](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/build.gradle#L21)) ```groovy allprojects { repositories { maven { name = "nexus" url = uri("https://nexus.banuba.net/repository/maven-releases") } ... } } ``` **Kotlin** (in `settings.gradle.kts`) ```kotlin dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { maven { name = "nexus" url = uri("https://nexus.banuba.net/repository/maven-releases") } } } ``` ### Add Packaging Options Settings Specify the following ```packaging options``` in your [build gradle](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/build.gradle#L46-L53) file: ```groovy android { ... packagingOptions { jniLibs { useLegacyPackaging = true } } ... } ``` ### Add dependencies Specify dependencies in the app [gradle](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/build.gradle#L63) file. ```groovy def banubaSdkVersion = '1.52.0' implementation "com.banuba.sdk:ffmpeg:5.3.0" implementation "com.banuba.sdk:camera-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:camera-ui-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:core-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:core-ui-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:ve-flow-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:ve-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:ve-ui-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:ve-gallery-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:ve-effects-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:effect-player-adapter:${banubaSdkVersion}" implementation "com.banuba.sdk:ar-cloud:${banubaSdkVersion}" implementation "com.banuba.sdk:ve-audio-browser-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:ve-export-sdk:${banubaSdkVersion}" implementation "com.banuba.sdk:ve-playback-sdk:${banubaSdkVersion}" ``` Add ```kotlin-parcelize``` plugin into plugins section of the [gradle](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/build.gradle#L63) file. ```groovy plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-parcelize' } ``` ## AndroidManifest Updates Add the following to your [AndroidManifest.xml](https://github.com/Banuba/ve-sdk-android-integration-sample/tree/main/app/src/main/AndroidManifest.xml#L27): 1. ```VideoCreationActivity``` – orchestrates the video editor screens ``` xml ``` > **Important** > Starting with version 1.51.0, themes are included in the SDK. For earlier versions, see the ```Removed styles``` section in the [changelog](https://www.notion.so/vebanuba/1-51-0-324fdb8b445b801b8f8bcceeb39066ad). 2. **Network permissions** (optional)– only required if using [Giphy](https://giphy.com/) stickers or downloading AR effects from the cloud. ```xml ``` **Note:** You'll also need a custom VideoCreationTheme [example](https://github.com/Banuba/ve-sdk-android-integration-sample/tree/main/app/src/main/res/values/themes.xml#L13) to style the editor UI. ## Koin Module Setup 1. Create [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/tree/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt) to initialize and customize the Video Editor SDK. 2. Inside it, add [SampleIntegrationKoinModule](https://github.com/Banuba/ve-sdk-android-integration-sample/tree/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L51) with your customizations: ``` kotlin class VideoEditorModule { ... private class SampleIntegrationKoinModule { val module = module { single(createdAtStart = true) { ArEffectsRepositoryProvider( arEffectsRepository = get(named("backendArEffectsRepository")) ) } single>( named("musicTrackProvider") ) { AudioBrowserMusicProvider() } ... } } } ``` 3. Include this module during SDK initialization: ``` diff fun initialize(applicationContext: Context) { startKoin { androidContext(applicationContext) allowOverride(true) // pass the customized Koin module that implements required dependencies. Keep order of modules modules( VeSdkKoinModule().module, VeExportKoinModule().module, VePlaybackSdkKoinModule().module, AudioBrowserKoinModule().module, // use this module only if you bought it ArCloudKoinModule().module, VeUiSdkKoinModule().module, VeFlowKoinModule().module, GalleryKoinModule().module, BanubaEffectPlayerKoinModule().module, + SampleIntegrationKoinModule().module, ) } } ``` ## Launch Initialize ```VideoEditorModule``` in your [Application](https://github.com/Banuba/ve-sdk-android-integration-sample/tree/main/app/src/main/java/com/banuba/example/integrationapp/SampleApp.kt#L42) class. ``` kotlin override fun onCreate() { super.onCreate() VideoEditorModule().initialize(this) } ``` Create SDK instance of ```EditorSdk``` with your license token. ``` kotlin val videoEditorSDK = EditorSdk.initialize(LICENSE_TOKEN) ``` :::warning 1. Returns ```null```l if the license token is invalid – verify your token 2. [Check license activation](https://github.com/Banuba/ve-sdk-android-integration-sample/tree/main/app/src/main/java/com/banuba/example/integrationapp/MainActivity.kt#L104) before starting the editor. 3. Expired/revoked licenses show a "Video content unavailable" screen ::: This example launches from camera ([full implementation](https://github.com/Banuba/ve-sdk-android-integration-sample/tree/main/app/src/main/java/com/banuba/example/integrationapp/MainActivity.kt#L35)): ```kotlin val createVideoRequest = registerForActivityResult(IntegrationAppExportVideoContract()) { exportResult -> exportResult?.let { //handle ExportResult object } } val intent = VideoCreationActivity.startFromCamera( context = this, // set PiP video configuration pictureInPictureConfig = null, // setup what kind of action you want to do with VideoCreationActivity // setup data that will be acceptable during export flow additionalExportData = null, // set TrackData object if you open VideoCreationActivity with preselected music track audioTrackData = null ) createVideoRequest.launch(intent) ``` --- ## Launching Photo Editor on Android Guide to launching Photo Editor SDK. ## Prerequisites :exclamation: The license token **IS REQUIRED** to use Photo Editor SDK in your app. Please check [Requirements](requirements-pe.md#license-token) out guide if the license token is not set. ## Initialize SDK Create an instance of ```BanubaPhotoEditor``` by using the license token ``` kotlin val photoEditorSDK = BanubaPhotoEditor.initialize(LICENSE_TOKEN) ``` ```photoEditorSDK``` is ```null``` when the license token is incorrect i.e. empty, truncated. If ```photoEditorSDK``` is not ```null``` you can proceed and start video editor. Next, we strongly recommend [checking](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/MainActivity.kt#L110) your license state before staring video editor ```kotlin photoEditorSDK.getLicenseState { isValid -> if (isValid) { // ✅ License is active, all good // Start Photo Editor SDK } else { // ❌ Use of Photo Editor is restricted. License is revoked or expired. } } ``` :::danger Photo editing content unavailable screen will appear if the user starts Photo Editor SDK with revoked or expired license. ::: ## Start editor Import classes ```kotlin import com.banuba.sdk.pe.BanubaPhotoEditor import com.banuba.sdk.pe.PhotoCreationActivity import com.banuba.sdk.pe.PhotoExportResultContract ``` Start Photo Editor SDK and handle exported results. [See example](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/MainActivity.kt#L79). ```kotlin val photoEditorExportResult = registerForActivityResult(PhotoExportResultContract()) { uri -> // Handle exported image result Log.d(TAG, "Image exported $uri") } // Start Photo Editor SDK photoEditorExportResult.launch(PhotoCreationActivity.startFromGallery(this)) ``` ## Disable publishing image to Gallery ```kotlin startPhotoEditor(PhotoCreationActivity.startFromGallery( this@MainActivity, config = PhotoEditorConfig.Builder(context = this).saveToGallery(false).build() )) ``` --- ## Banuba Photo Editor SDK Requirements on Android Guide contains general requirements for using Photo Editor SDK on Android. ## License Token Before you commit to a license, you are free to test all the features of the SDK for free. The trial period lasts 14 days. Send us a message to start the [Photo Editor SDK trial](https://www.banuba.com/photo-editor-sdk#form). We will get back to you with the trial token. Feel free to contact us if you have any questions regarding [Photo Editor SDK](https://www.banuba.com/support). ## Project settings This is what you need to run the AI Video Editor SDK: - Kotlin 1.8+ or Java 17 - Android OS 6.0 or higher with Camera 2 API - OpenGL ES 3.0 (3.1 for Neural networks on GPU) - :white_check_mark: arm64-v8a , :white_check_mark: armv7, :exclamation: x86-64 limited support, :x: x86 - no support ## Supported media formats | Images | | ----------- | | .jpg, .gif, .heic, .png, .nef, .cr2, .jpeg, .raf, .bmp ## SDK size | Photo Editor | Total size | |:------------:|:----------:| |:white_check_mark:| 65 MB | --- ## Requirements # Banuba Video Editor SDK Requirements on Android ## License Token Before you commit to a license, you are free to test all the features of the SDK for free. The trial period lasts 14 days. Send us a message to start the [Video Editor SDK trial](https://www.banuba.com/video-editor-sdk#form). We will get back to you with the trial token. Feel free to contact us if you have any questions regarding [Video Editor SDK](https://www.banuba.com/support). ## Project settings This is what you need to run the AI Video Editor SDK: - Kotlin 2.1+ or Java 17 - Android OS 8.0 or higher with Camera 2 API - OpenGL ES 3.0 (3.1 for Neural networks on GPU) - :white_check_mark: arm64-v8a , :white_check_mark: armv7, :exclamation: x86-64 limited support, :x: x86 - no support ## Supported media formats | Audio | Video | Images | |-------------------------------------| --------- | ----------- | | .aac, .mp3, .wav, .ogg, .m4a, .flac |.mp4, .mov | .jpg, .gif, .heic, .png, .nef, .cr2, .jpeg, .raf, .bmp ## SDK size Banuba Video Editor SDK with all the core editing features only adds 25 Mb of space to your app’s download size. This parameter can change based on the number of features you want. |SDK| Total size | |:------------|:----------:| |Banuba Video Editor SDK (core editor)| 25 Mb | |Banuba Video Editor SDK (full bundle)| 45 Mb | |Video Editor with Photo Editor | 70 Mb | |Video Editor with face augmented reality features | 45 - 90 Mb | --- ## FAQ on Android These are the answers to the most common questions asked about our SDK. ### I want to start VideoEditor with a preselected audio track To open Video Editor SDK you should create an intent by utilizing any avilable function inside **VideoCreationActivity**: **startFromCamera()**, **startFromTrimmer()** or **startFromEditor()**. All these functions have an argument called **audioTrackData** where you should pass preselected audio track or null (by default). For example, to open an SDK from the camera screen with the track use the code snippet below: ```kotlin startActivity( VideoCreationActivity.startFromCamera( context = applicationContext, audioTrackData = preselectedTrackData ) ) ``` **audioTrackData** is an object of TrackData class ```kotlin data class TrackData( val id: UUID, val title: String, val localUri: Uri, val artist: String? = null ) ``` ### How to add other text fonts that are used in the editor screen To add other text fonts that are used in the editor screen follow the next steps: 1. Add font files to the `app/src/main/res/font/` directory; 2. Add fonts names to the ```strings.xml ``` resource file: ```xml Font 1 Title Font N Title ``` 3. Add `font_resources.xml` with fonts array declaration to the `app/src/main/res/values/` directory. The format of `font_resources.xml` should be the next one: ```xml @array/font_1_resource @array/font_N_resource @string/font_1_title @font/font_1 @string/font_N_title @font/font_N ``` 4. The final step is to pass your custom `font_resources` id to the `MainTextOnVideoTypefaceProvider` in the ```SampleIntegrationKoinModule``` to override the default implementation: ```kotlin single { MainTextOnVideoTypefaceProvider( context = get(), fontsArrayResId = R.array.font_resources ) } ``` ### Optimizing app size The easiest way to gain immediate app size savings when publishing to Google Play is by uploading your app as an [**Android App Bundle**](https://developer.android.com/guide/app-bundle), which is a new upload format that includes all your app’s compiled code and resources. Google Play’s new app serving model then uses your app bundle to generate and serve optimized APKs for each user’s device configuration, so they download only the code and resources they need to run your app. As a result, the final size of our library for one of the platform types (`armeabi-v7a`,` arm64-v8a`, `x86`,` x86_64`) will be **24-26 MB** less than indicated in the documentation ### How do I change the language (how do I add new locale support)? There is no special language switching mechanism in the Video Editor SDK. Out of the box, the VE SDK supports `English` locale. If you need to support any other locales, you can do it according to the standard Android way. See how [Create locale directories and resource files](https://developer.android.com/training/basics/supporting-devices/languages#CreateDirs) for more details. After adding a new locale resource file into your application with integrated VE SDK, you need to re-define the VE SDK strings keys with new locale string values. To do that you need to add all needed string keys in the new locale `strings.xml` file. The newly added locale will be applied after the device language is changed by system settings. If you need to change language programmatically in your application, see the next links how it can be done: [one](https://www.geeksforgeeks.org/how-to-change-the-whole-app-language-in-android-programmatically/), [two](https://medium.com/swlh/android-app-specific-language-change-programmatically-using-kotlin-d650a5392220) ### How do I use the Video Editor several times from different entry points? Before you want to use VideoEditor again, you need to release ```Video Editor SDK```: ```kotlin private fun releaseVideoEditor() { releaseUtilityManager() stopKoin() videoEditor = null } private fun releaseUtilityManager() { val utilityManager = try { getKoin().getOrNull() } catch (e: InstanceCreationException) { Log.w(TAG, "EditorUtilityManager was not initialized!", e) null } utilityManager?.release() } ``` ```EditorUtilityManager``` is NULL when the token is expired or revoked. ### I want to change icons and name for effects. Effect customization is implemented by android resources with well-defined names which follow a strict scheme. | Customization | Resource type | Resource name template | Example | :---: | :---: | :---: | :---: | | Title | string | visual_effect_\{id\}, time_effect_\{id\} | visual_effect_flash | Icon | drawable | ic_visual_effect_\{id\}, ic_time_effect_\{id\} | ic_time_effect_rapid | Color | color | visual_effect_color_\{id\}, time_effect_color_\{id\} | visual_effect_color_vhs To change appearance o the effect, you should place any android resources named according to the scheme presented above into res folder of your app. The resource depends on the item you want to customize (string for the title, drawable for the icon, color for the color on the timeline). Effects identifiers are presented in the table below: | Effect | Type | String identifier | Default icon | | :---------- | :---:| :--------------: | :----------: | | Acid-whip | visual | acid_whip| ic_visual_effect_acid_whip | Cathode | visual | cathode | ic_visual_effect_cathode | Flash | visual | flash | ic_visual_effect_flash | Glitch | visual | glitch | ic_visual_effect_glitch | Glitch 2 | visual | glitch2 | ic_visual_effect_glitch2 | Glitch 3 | visual | glitch3 | ic_visual_effect_glitch3 | Heat map | visual | heat_map | ic_visual_effect_heat_map | DSLR Kaleidoscope | visual | dslr_kaleidoscope | ic_visual_effect_dslr_kaleidoscope | Kaleidoscope | visual | kaleidoscope | ic_visual_effect_kaleidoscope | Lumiere | visual | lumiere | ic_visual_effect_lumiere | Pixel dynamic | visual | pixel_dynamic | ic_visual_effect_pixel_dynamic | Pixel static | visual | pixel_static | ic_visual_effect_pixel_static | Polaroid | visual | polaroid | ic_visual_effect_polaroid | Rave | visual | rave | ic_visual_effect_rave | Soul | visual | soul | ic_visual_effect_soul | Stars | visual | stars | ic_visual_effect_stars | Transition 1 | visual | transition1 | ic_visual_effect_transition1 | Transition 2 | visual | transition2 | ic_visual_effect_transition2 | Transition 3 | visual | transition3 | ic_visual_effect_transition3 | Transition 4 | visual | transition4 | ic_visual_effect_transition4 | TV Foam | visual | tv_foam | ic_visual_effect_tv_foam | DV Cam | visual | dv_cam | ic_visual_effect_dv_cam | VHS | visual | vhs | ic_visual_effect_vhs | VHS 2 | visual | vhs2 | ic_visual_effect_vhs2 | Zoom | visual | zoom | ic_visual_effect_zoom | Zoom 2 | visual | zoom2 | ic_visual_effect_zoom2 | Slow mo | time | slow_motion | ic_time_effect_slow_motion | Rapid | time | rapid | ic_time_effect_rapid For example, to change the title of ```Flash``` visual effect to ```SuperFlash``` add it in ```strings.xml``` in your app. ```xml SuperFlash ``` You can change the color on the timeline for any visual effect. For example, for ```VHS``` you should add color resource with the name ```visual_effect_color_vhs``` into ```colors.xml``` file in your app. ### I want to change the order of masks, video effects or filters. The SDK allows to reorder masks and filters in the way you need. To achieve this, create a class ```CustomColorFilterOrderProvider``` and implement ```OrderProvider```: ```kotlin class CustomColorFilterOrderProvider : OrderProvider { override fun provide() = listOf( "egypt", "byers", "chile", "hyla", "new_zeland", "korben", "canada", "remy", "england", "retro", "norway", "neon", "japan", "instant", "lux", "sunset", "bubblegum", "chroma", "lilac", "pinkvine", "spark", "sunny", "vinyl", "glitch", "grunge" ) } ``` :::important These are names of specific color filters located in ```assets/bnb-resources/luts```. ::: Next, use ```CustomColorFilterOrderProvider``` in [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L60) ```kotlin single(named("colorFilterOrderProvider")) { CustomColorFilterOrderProvider() } ``` ### Is it possible to disable the transition effects? Transitions are visual effects applying to the segue between two videos. They are provided with the Banuba Video Editor SDK **by default**. To disable or enable transitions, set the `supportsTransitions` flag in the `EditorConfig` class to false or true respectively: ``` kotlin single { EditorConfig(supportsTransitions = false) } ``` :::important Transition effects are not being played if the closest video (either to the left or to the right of the transition icon) is very short. ::: ### How can I convert one or several still images to a video programmatically? If you would like to create a video from the images instances without opening the Video Editor, you can use the methods from the ```Utils``` object in the [GitHub Sample](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/Utils.kt#L72-L131). ### How to change the style appearance of the SDK? Extend ```VideoCreationTheme``` style to customize Video Editor appearance for your app. ```xml ``` Specify your style in ```AndroidManifest.xml``` file for ```VideoCreationActivity```. ```xml ``` [GitHub example](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/res/values/themes.xml) ### Is it possible to disable the Trim screen? It is possible to turn off the trimmer screen after the camera screen. The trimmer screen will still be accessible after importing media files from the gallery. To disable it, just change the `supportsTrimRecordedVideo` property to `false` in the `EditorConfig`: ``` kotlin single { EditorConfig(supportsTrimRecordedVideo = false) } ``` ### How to change the video scaling on the editor screen? Yon can change video scaling on the editor screen while playback by providing ```PlayerScaleType``` [VideoEditorModule](https://github.com/Banuba/ve-sdk-android-integration-sample/blob/main/app/src/main/java/com/banuba/example/integrationapp/VideoEditorModule.kt#L60). To ensure that the video will be fully shown - use ```CENTER_INSIDE``` (keep in mind that if device and video resolutions are different black lines will appear), to fill the screen - use ```FIT_SCREEN_HEIGHT``` (it fills the screen only if video has aspect ratio 9:16) ``` kotlin factory(named("editorVideoScaleType"), override = true) { PlayerScaleType.CENTER_INSIDE } ``` The default value is ```PlayerScaleType.FIT_SCREEN_HEIGHT```. ### How to collect logs when I encounter an issue? If you encounter a crash or other issue and are unsure how to provide logs to the support team, please refer to the official Android documentation on how to capture a bug report: [https://developer.android.com/studio/debug/bug-report](https://developer.android.com/studio/debug/bug-report) After following the instructions, please send the generated bug report file to the [support team](https://www.banuba.com/support) for further investigation. ### FFmpeg build issue Below are the steps to resolve the issue while building the project. 1. Add the ```android.bundle.enableUncompressedNativeLibs=false``` in the ```gradle.properties``` ``` properties android.bundle.enableUncompressedNativeLibs=false ``` 2. Add ```android:extractNativeLibs="true"``` in ```AndroidManifest.xml``` file ``` xml ``` ### How to integrate custom FFmpeg dependency. Check out [step-by-step guide](ffmpeg.md) to integrate custom FFmpeg dependency. --- ## Video Templates on Android Templates let users create stunning videos quickly and easily using predefined sets of effects, transitions, and music. All it takes to make a shareable piece is changing the placeholders. With templates, even people who are new to video editing or just lack time can make impressive content in minutes.       :::important The ```Video Templates``` is not enabled by default. Contact Banuba representatives to know more. ::: ## Launch Video Templates Use a new entry point in `VideoCreationActivity` to launch the Video Editor SDK from Video templates. ```kotlin val intent = VideoCreationActivity.startFromTemplates(Context) ``` ## Setup Custom Templates :::important Use this method if you have an agreement with Banuba for the delivery of additional templates and have received the corresponding URL. By default, the SDK is delivered with predefined configuration to load Banuba templates. ::: Use `TemplatesConfig` to enable templates in your app. Two options are available — add `TemplatesConfig` to your Video Editor Koin module. ### By URL ```kotlin single { TemplatesConfig( url = // your endpoint i.e. "https://" ) } ``` ### By secret key :::important Requires a `secret` key provided by your Banuba representative. ::: ```kotlin single { TemplatesConfig( url = "", secret = // set your secret key provided by Banuba ) } ``` --- ## AI Clipping on Flutter The ```AI Clipping``` feature automates the video creation process by leveraging the power of artificial intelligence. The neural network transforms raw input into ready-to-post videos with various transitions, effects, and a precise music match. Here is how users can interact with it: 1. User selects clips and music. People can choose their desired clips and accompanying music within the app. 2. AI trims the videos. The AI algorithm intelligently trims the selected clips to match the tempo and rhythm of the chosen track. 3. AI adds various effects. AI Clipping enhances the content by adding a variety of effects to create visually stunning content. 4. User exports, edits, or regenerates the clip. Upon completion, users have the flexibility to export the video as is, make further edits, or regenerate the clip for a fresh perspective. 5. Regardless of the user’s editing skills, with the help of Auto Cut, everyone can get a stunning video within seconds. ## Supported music providers 1. [Soundstripe](audio_browser_guide.md#soundstripe) 2. [Banuba Music](audio_browser_guide.md#banuba-music) :::note Please contact Banuba representatives to know more about using the ```Banuba music``` with ```AI Clipping```. ::: ## Usage ### Setup configuration Specify instance of ```AiClipping``` in ```FeaturesConfig``` builder: :::important Contact Banuba representatives to get trial keys for ```audioDataUrl``` and ```audioTracksUrl``` use in production. ::: ```dart final config = FeaturesConfigBuilder() .setAiClipping( AiClipping( audioDataUrl: "...", audioTracksUrl: "..." ) ) ... .build(); ``` ### Launch AI Clipping :::note Video creation with AI Clipping is available on Gallery screen by default. ::: For better experience we added new entry point to `VeSdkFlutter` for opening AI Clipping as a separate mode. In this scenario the user starts from the gallery screen and is taken to AI Clipping screen after selecting media. ```dart Future _startVideoEditorInAiClippingMode() async { final config = FeaturesConfigBuilder() .setAudioBrowser(...) .setAiClipping(...) .build(); try { dynamic exportResult = await _veSdkFlutterPlugin .openAiClippingScreen(_licenseToken, config); _handleExportResult(exportResult); } on PlatformException catch (e) { _handlePlatformException(e); } ``` --- ## Audio Browser on Flutter ```Audio Browser``` - a specific module and set of screens that include the built-in support of browsing and applying audio content within the Video Editor. The user does not leave the SDK while using audio. :::note Banuba does not deliver audio content for the Video Editor SDK. The Video Editor can apply audio files stored on the device. The SDK is not responsible for downloading audio content except for [Soundstripe](https://www.soundstripe.com/). ::: Audio Browser is a specific module that allows to browse, play and apply audio content within video editor. It supports 3 sources for audio content: 1. Soundstripe - includes built in integration with Soundstripe API. 2. Banuba Music - includes built in integration with Banuba Music. 3. My Library - includes audio content available on the user's device ## Usage ### Soundstripe [Soundstripe](https://www.soundstripe.com/) is a service for providing the best audio tracks for creating video content. Your users will be able to add audio tracks while recording or editing video content. :::note The feature is not activated by default. Please contact Banuba representatives to know more about using this feature. ::: Specify the instance of ```AudioBrowser``` in ```FeaturesConfig``` builder with Soundstripe source: ```dart final config = FeaturesConfigBuilder() .setAudioBrowser(AudioBrowser.fromSource(AudioBrowserSource.soundstripe)) ... .build(); ``` ### Banuba Music Over 35 GB of royalty-free tracks available from within the Video Editor SDK. Your users could check them out through an inbuilt music browser and legally include them in their content. :::note The feature is not activated by default. Please contact Banuba representatives to know more about using this feature. ::: Specify the instance of ```AudioBrowser``` in ```FeaturesConfig``` builder with Banuba Music source and params: ```dart final config = FeaturesConfigBuilder() .setAudioBrowser(AudioBrowser.fromSource(AudioBrowserSource.banubaMusic)) ... .build(); ``` ### My Library ```My Library``` is a default implementation in AudioBrowser . It allows the user to apply audio that is available on a device. Specify the instance of ```AudioBrowser``` in ```FeaturesConfig``` builder with local source: ```dart final config = FeaturesConfigBuilder() .setAudioBrowser(AudioBrowser.fromSource(AudioBrowserSource.local)) ... .build(); ``` --- ## Camera screen on Flutter ## Usage Specify instance of ```CameraConfig``` in ```FeaturesConfig``` builder: ```dart final config = FeaturesConfigBuilder() .setCameraConfig( CameraConfig( supportsBeauty: false, supportsColorEffects: false, supportsMasks: false, recordModes: [RecordMode.video, RecordMode.photo], autoStartLocalMask: null ) ) ... .build() ``` ### Options - ```supportsBeauty``` - Determines whether the camera supports beauty effect. Default value is ```true```. - ```supportsColorEffects``` - Determines whether the camera supports color effects. Default value is ```true```. - ```supportsMasks``` - Determines whether the camera supports visual effects. Default value is ```true```. - ```recordModes``` - Determines which recording modes are supported. Default value is ```[RecordMode.video, RecordMode.photo]``` - ```autoStartLocalMask``` - Determines whether the camera starts with preselected mask. Default value is ```null``` --- ## Closed Captions on Flutter AI Captions are a textual representation of the audio within a media file. Over 80% of videos played on mobile devices don’t have sound turned on. This means many forms of content (e.g. skits, monologues, educational clips, etc.) will be skipped if there are no subtitles. But making captions by hand is tedious. AI-generated subtitles solve this issue, as they are created and placed automatically. The users can then edit the text as well as change its style and color. [AWS Transcribe service](https://docs.aws.amazon.com/transcribe/) is used to generate captions. ## Supported languages - Arabic - English - Mandarin - Spanish - Portuguese ## Usage Specify instance of ```Captions``` in ```FeaturesConfig``` builder: :::important A trial option for AI Captions Please contact Banuba representatives before use in production. ::: ```dart final config = FeaturesConfigBuilder() .setCaptions( Captions( uploadUrl: "https://internal.transcribe.banuba.net", transcribeUrl: "https://rest.internal.transcribe.banuba.net/transcribe/v1/status", apiKey: "CheiYaaphoK6eungecheec4eingeik9shaijiech" ) ) ... .build(); ``` --- ## Cover Screen on Flutter Cover image screen allows users to pick any frame of video as image or choose an image from gallery. ## Usage Specify instance of ```ConfigConfig``` in ```FeaturesConfigBuilder``` builder: ```dart final config = FeaturesConfigBuilder() .setCoverConfig(CoverConfig( supportsCoverScreen: false )) .build(); ``` ### Options - ```supportsCoverScreen``` - Determines whether the Cover screen supports. Default value is ```true```. --- ## Draft Configuration on Flutter Drafts are enabled by default, asks the user to save a draft before leave any VideoEditor screen. ## Usage Specify instance of ```DraftsConfig``` in ```FeaturesConfig``` builder to change drafts configuration: ```dart final config = FeaturesConfigBuilder() .setDraftConfig(DraftsConfig.fromOption(DraftsOption.auto)) ... .build(); ``` ### Options - ```DraftsOption.askToSave``` - drafts enabled, asks the user to save a draft - ```DraftsOption.auto``` - drafts enabled, saved by default without asking the user - ```DraftsOption.closeOnSave``` - drafts enabled, asks the user to save a draft without export - ```DraftsOption.disable``` - disabled drafts --- ## Editor screen on Flutter ## Usage Specify instance of ```EditorConfig``` in ```FeaturesConfig``` builder: ```dart final config = FeaturesConfigBuilder() .setEditorConfig( EditorConfig( enableVideoAspectFill: false, supportsColorEffects: false, supportsVisualEffects: false, supportsVoiceOver: false, supportsAudioEditing: false ) ) ... .build() ``` ### Options - ```enableVideoAspectFill``` - Fill video aspect on the editor screen while playback. Default value is ```true```. - ```supportsColorEffects``` - Determines whether the editor supports color effects. Default value is ```true```. - ```supportsVisualEffects```- Determines whether the editor supports visual effects. Default value is ```true```. - ```supportsVoiceOver``` - Determines whether the editor supports voice over. Default value is ```true```. (Android only) - ```supportsAudioEditing``` - Determines whether the editor supports audio editing. Default value is ```true```. (Android only) --- ## Editor V2 on Flutter ## Overview With the new interface, better controls, and additional quality of life improvements, making stunning videos is easier and more fun than ever. Design and user experience principles are constantly evolving. To keep up with the latest developments and best practices, our team has completely redesigned the Video Editor SDK to be as convenient and enjoyable as possible. ## Usage Set the ```.enableEditorV2``` to true in the ```FeaturesConfigBuilder```: ```dart final config = FeaturesConfigBuilder() .enableEditorV2(true) ... .build(); ``` --- ## Export Media on Flutter ## Overview Video Editor SDK allows to export a number of video files with various resolutions and other configurations. Video is exported as ```.mp4``` for Android and ```.mov``` for IOS file. Refer to our main docs [Android](https://docs.banuba.com/ve-pe-sdk/docs/android/guide_export) and [IOS](https://docs.banuba.com/ve-pe-sdk/docs/ios/guide_export) to learn more about media export in the Video Editor. ## Implement export flow :::note Default implementation exports single video file with auto quality(based on device hardware capabilities). ::: Create a new instance of ```ExportData``` to export 2 videos with ```HD``` and ```auto``` qualities: ```dart const exportData = ExportData(exportedVideos: [ ExportedVideo( fileName: "export_hd_720p", videoResolution: VideoResolution.hd720p ), ExportedVideo( fileName: "export_auto", videoResolution: VideoResolution.auto )] ); ``` Next, specify it in the [start method](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/lib/main.dart#L66) of the Video Editor: ```diff try { dynamic exportResult = await _veSdkFlutterPlugin.openCameraScreen( _licenseToken, config, + exportData: exportData ); _handleExportResult(exportResult); } on PlatformException catch (e) { _handlePlatformException(e); } ``` ## Use AVC codec You can specify ```H264(AVC_PROFILES)``` by setting ```false``` to ```useHevcIfPossible```. ```diff const exportData = ExportData(exportedVideos: [ ExportedVideo( fileName: "export_hd", videoResolution: VideoResolution.hd720p, + useHevcIfPossible: false )] ); ``` ## Add watermark Watermark is not added to exported video by default. Specify your watermark in the [pubspec.yaml](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/pubspec.yaml#L50) and provide it to the ```ExportData``` instance: ```diff const exportData = ExportData(exportedVideos: [ ExportedVideo( fileName: "export_hd", videoResolution: VideoResolution.hd720p )], + watermark: Watermark( + imagePath: "assets/watermark.png", + alignment: WatermarkAlignment.bottomRight + ) ); ``` --- ## Banuba Photo Editor Flutter on Flutter ## Overview [Banuba Photo Editor SDK](https://www.banuba.com/photo-editor-sdk) allows you to quickly add photo functionality and effects into your mobile app. ## Usage ### License Before you commit to a license, you are free to test all the features of the SDK for free. The trial period lasts 14 days. To start it, [send us a message](https://www.banuba.com/photo-editor-sdk#form). We will get back to you with the trial token. Feel free to [contact us](https://www.banuba.com/support) if you have any questions. ## Installation Run in Terminal to install Photo Editor Flutter plugin ``` $ flutter pub add pe_sdk_flutter ``` or specify the package in your ```pubspec.yaml``` file ``` dependencies: pe_sdk_flutter: ^0.5.0 ``` ## Integration guide Please follow our [Integration Guide](https://docs.banuba.com/ve-pe-sdk/docs/flutter/pe_integration) to complete full integration. ## Launch Set Banuba license token [within the app](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/lib/main.dart#L10) ### Android Run ```flutter run``` in terminal to launch the app on a device or use IDE i.e. Intellij, VC, etc. to launch the app. ### iOS 1. Install CocoaPods dependencies. Open **ios** directory and run ```pod install``` in terminal. 2. Open **Signing & Capabilities** tab in Target settings and select your Development Team. 3. Run ```flutter run``` in terminal to launch the app on a device or launch the app in IDE i.e. XCode, Intellij, VC, etc. ## Dependencies | | Version | | --------- |:-------:| | Dart | 3.3.0 | | Flutter | 3.19.2 | | Android | 8.0+ | | iOS | 15.0+ | --- ## Integration Guide on Flutter This guide helps to complete full Photo Editor SDK integration. ## Import it Use in your Dart code ``` dart import 'package:pe_sdk_flutter/pe_sdk_flutter.dart'; ``` ## Configuration ### Android #### Update gradle files :::important if your project supports [Flutter Gradle plugin](https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply#androidsettings-gradle). ::: Update your [project gradle](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/android/build.gradle#L1) with the following code: ``` buildscript { ext.kotlin_version = '2.1.0' repositories { google() mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:8.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } ``` ### IOS #### Add specs to Podfile Add the following specs at the top of your [Podfile](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/ios/Podfile) ``` platform :ios, '15.0' source 'https://cdn.cocoapods.org/' source 'https://github.com/Banuba/specs.git' source 'https://github.com/sdk-banuba/banuba-sdk-podspecs.git' ``` #### Add permissions Specify the required iOS permissions used by the SDK in your [Info.plist](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/ios/Runner/Info.plist) ``` NSPhotoLibraryUsageDescription This app requires access to the photo library. ``` ## Limit processor architectures on Android Banuba Photo Editor on Android supports the following processor architectures - ```arm64-v8a```, ```armeabi-v7a```, ```x86-64```. Please keep in mind that each architecture adds extra MBs to your app. To reduce the app size you can filter architectures in your ```app/build.gradle file```. ```groovy ... defaultConfig { ... // Use only ARM processors ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' } } ``` --- ## Stickers on Flutter Stickers are interactive objects (gif images) that can be added to the video recording. ## Giphy Video Editor uses [Giphy service](https://developers.giphy.com/docs/api/) for loading stickers. Any sticker effect is a GIF file. ## Usage Specify instance of ```GifPickerConfig``` in ```FeaturesConfig```: :::important To use stickers in your project you need to request personal [Giphy API key](https://support.giphy.com/hc/en-us/articles/360020283431-Request-A-GIPHY-API-Key) ::: ```dart final config = FeaturesConfigBuilder() .setGifPickerConfig( GifPickerConfig( giphyApiKey: "...", mode: GiphyMode.search, ids: ["...", "..."] ) ) ... .build(); ``` --- ## Banuba Video Editor Flutter ## Overview Build apps like TikTok and Videoshop faster with the Banuba [Video Editor SDK](https://www.banuba.com/video-editor-sdk-api-social-media-app) for Flutter. With an extensive feature set, simple integration process, and user-friendly interface, it is a comprehensive toolkit that will bring your app to the level of industry giants. Its flexibility allows you to only pick the features that you need, optimizing the app’s download size and license costs. Banuba Video Editor Flutter SDK offers [certain features that few competitors do](https://www.banuba.com/blog/best-video-editor-sdks-compared), including high-quality Face AR masks and AI video editing tools. Features: - Recording - Trimming & merging - Sound track editing - Hands-free mode - Transition effects - Color filters (LUTs) - Text, picture, and GIF overlays - 3D masks - Beauty effects - Picture-in-picture (Duets) - AR filters - AI clipping - AI video generation - AI subtitles - Royalty-free music library - Music provider integration And more Refer to the documentation for more details: - [Android](https://docs.banuba.com/ve-pe-sdk/docs/android/requirements-ve/) - [iOS](https://docs.banuba.com/ve-pe-sdk/docs/ios/requirements) Video Editor SDK **works offline**, and doesn’t send, store, or process any user information, making it **compliant with GDPR and other data protection regulations**. ## Usage ### License [Start a 14-day free trial](https://www.banuba.com/video-editor-sdk#form) and see how the Video Editor SDK Flutter plugin works. No credit card information is needed. Feel free to [contact us](https://www.banuba.com/support) if you have any questions regarding this plugin. ## Installation Run in Terminal to install Video Editor Flutter plugin ``` $ flutter pub add ve_sdk_flutter ``` or specify the package in your ```pubspec.yaml``` file ``` dependencies: ve_sdk_flutter: ^0.43.0 ``` ## Integration guide Please follow our [Integration Guide](https://docs.banuba.com/ve-pe-sdk/docs/flutter/ve_integration) to complete full integration. ## Launch Set Banuba license token [within the app](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/lib/main.dart#L10) ### Android Run ```flutter run``` in terminal to launch the app on a device or use IDE i.e. Intellij, VC, etc. to launch the app. ### iOS 1. Install CocoaPods dependencies. Open **ios** directory and run ```pod install``` in terminal. 2. Open **Signing & Capabilities** tab in Target settings and select your Development Team. 3. Run ```flutter run``` in terminal to launch the app on a device or launch the app in IDE i.e. XCode, Intellij, VC, etc. ## Dependencies | | Version | | --------- |:-------:| | Dart | 3.3.0 | | Flutter | 3.19.2 | | Android | 8.0+ | | iOS | 15.0+ | --- ## Integration Guide on Flutter(Flutter) This guide helps to complete full Video Editor SDK integration. ## Import it Use in your Dart code ``` dart import 'package:ve_sdk_flutter/ve_sdk_flutter.dart'; ``` ## Configuration ### Android #### Update gradle files :::important if your project supports [Flutter Gradle plugin](https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply#androidsettings-gradle). ::: Update your [project gradle](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/android/settings.gradle#L12) with the following code: ```groovy buildscript { ext.kotlin_version = '1.8.22' repositories { google() mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:8.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } ``` ### IOS #### Add specs to Podfile Add the following specs at the top of your [Podfile](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/ios/Podfile) ``` platform :ios, '15.0' source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/Banuba/specs.git' source 'https://github.com/sdk-banuba/banuba-sdk-podspecs.git' ``` #### Add permissions Specify the required iOS permissions used by the SDK in your [Info.plist](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/ios/Runner/Info.plist) ``` NSAppleMusicUsageDescription This app requires access to the media library NSCameraUsageDescription This app requires access to the camera. NSMicrophoneUsageDescription This app requires access to the microphone. NSPhotoLibraryUsageDescription This app requires access to the photo library. ``` ## Add AR effects [Banuba Face AR SDK](https://www.banuba.com/facear-sdk/face-filters) product is used on camera and editor screens for applying various AR effects while making video content. 1. Android - add effects to the project by the path [android/app/src/main/assets/bnb-resources/effects](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/android/app/src/main/). 2. iOS - add the effect to resource folder ```bundleEffects```. Make sure to select the "Copy items if needed" and "Create folder references" checkboxes while adding effects to the ```bundleEffects``` folder. ### Android Preview files are in [drawable-xhdpi](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/android/app/src/main/res/drawable-xhdpi), [drawable-xxhdpi](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/android/app/src/main/res/drawable-xxhdpi), [drawable-xxxhdpi](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/android/app/src/main/res/drawable-xxxhdpi) folders. Keep in mind that ```drawable-xxxhdpi``` contains files with the highest resolution. Additionally, you can copy paste just one set of previews if it meets your requirements. ### iOS Copy the ```ColorEffectsPreview``` folder from [example's asset catalog](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/ios/Runner/Assets.xcassets) to your app's asset catalog. ## Disable Face AR SDK ### Android Set the ```ENABLE_FACE_AR``` flag to the [gradle.properties](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/android/gradle.properties#L4): ```diff org.gradle.jvmargs=-Xmx4096M android.useAndroidX=true android.enableJetifier=true + ENABLE_FACE_AR=false ``` ### IOS Set the environment ```ENABLE_FACE_AR``` flag the the [PodFile](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/ios/Podfile#L10): ```diff ... ENV['COCOAPODS_DISABLE_STATS'] = 'true' + ENV['ENABLE_FACE_AR'] = 'false' project 'Runner', { 'Debug' => :debug, 'Profile' => :release, 'Release' => :release, } ... ``` ## Enable Android Photo Picker Set the ```ENABLE_GALLERY``` flag to the [gradle.properties](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/android/gradle.properties#L4): ```diff org.gradle.jvmargs=-Xmx4096M android.useAndroidX=true android.enableJetifier=true + ENABLE_GALLERY=false ``` ## Limit processor architectures on Android Banuba Video Editor on Android supports the following processor architectures - ```arm64-v8a```, ```armeabi-v7a```, ```x86-64```. Please keep in mind that each architecture adds extra MBs to your app. To reduce the app size you can filter architectures in your ```app/build.gradle file```. ```groovy ... defaultConfig { ... // Use only ARM processors ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' } } ``` ## Customizations ### Usage Create instance of the ```FeaturesConfig``` to apply various Video Editor configurations. Pass the ```FeaturesConfig``` instance to any Video Editor [start method](https://github.com/Banuba/ve-sdk-flutter/blob/master/example/lib/main.dart#L43-L124). For example: ```dart Future _startVideoEditorInCameraMode() async { final config = FeaturesConfigBuilder() .setAudioBrowser(AudioBrowser.fromSource(AudioBrowserSource.local)) // ... .build(); try { dynamic exportResult = await _veSdkFlutterPlugin.openCameraScreen(_licenseToken, config); _handleExportResult(exportResult); } on PlatformException catch (e) { _handlePlatformException(e); } } ``` --- ## Video Duration on Flutter ```VideoDurationConfig``` is responsible for customizing video recording durations. ## Usage Specify instance of ```VideoDurationConfig``` in ```FeaturesConfig```: ```dart final config = FeaturesConfigBuilder() .setVideoDurationConfig(VideoDurationConfig( maxTotalVideoDuration: 180.0, videoDurations: [180.0, 120.0, 60.0] )) ... .build() ``` --- ## Video Templates on Flutter Templates let users create stunning videos quickly and easily using predefined sets of effects, transitions, and music. All it takes to make a shareable piece is changing the placeholders. With templates, even people who are new to video editing or just lack time can make impressive content in minutes.       :::important The ```Video Templates``` is not enabled by default. Contact Banuba representatives to know more. ::: ## Launch Video Templates ```dart Future _startVideoEditorInCameraMode() async { // Specify your Config params in the builder below final config = FeaturesConfigBuilder() ... .build(); try { dynamic exportResult = await _veSdkFlutterPlugin .openTemplatesScreen(_licenseToken, config); _handleExportResult(exportResult); } on PlatformException catch (e) { _handlePlatformException(e); } } ``` ## Setup Custom Templates :::important Use this method if you have an agreement with Banuba for the delivery of additional templates and have received the corresponding URL. By default, the SDK is delivered with predefined configuration to load Banuba templates. ::: Two options are available. ### By URL ```dart final config = FeaturesConfigBuilder() .setTemplatesConfig(TemplatesConfig(url: YOUR_URL)) ... .build(); ``` ### By secret key :::important Requires a `secret` key provided by your Banuba representative. ::: ```dart final config = FeaturesConfigBuilder() .setTemplatesConfig(TemplatesConfig(secret: 'YOUR_SECRET_KEY')) ... .build(); ``` ## Template Builder       :::important This feature is currently available on iOS only (starting from version 1.51.3). *** Access requires a specific license token feature. Please contact your Banuba representative to enable it. ::: Template Builder allows users to create custom video templates with transitions, effects, music, and text. Others can use these as starting points by replacing the media placeholders. ### Key Features - **No-Code Template Creation:** Client teams build branded video templates in minutes without engineering support. - **Flexible Parameters:** Define music, transitions, clip lengths, FX, text, and metadata tags. - **Fillable Media Slots:** Set dedicated media placeholders for end-users to insert their own videos. ### Launch Template Builder ```dart final config = FeaturesConfigBuilder() .setTemplatesConfig(TemplatesConfig( enableBuilder: true, termsOfUseURL: )) .build(); await _veSdkFlutterPlugin.openTemplatesScreen(_licenseToken, config); ``` ### Terms of Use URL The Template Builder includes a confirmation step before a template is published. At this step, the user sees a message similar to: > *«By publishing, you confirm that your content complies with the Terms of Use and does not infringe third-party rights.»* The **Terms of Use** link in that message leads to a page where you define the full legal terms that apply to content created and published by your team members using the Template Builder. Setting this URL ensures that your organisation’s usage policies, IP guidelines, and content restrictions are clearly communicated to anyone who can publish templates. The link must point to a publicly accessible web page (e.g. your company’s Terms of Use or a dedicated policy document) and the URL **must be valid and reachable**. --- ## Customization Options Video Editor SDK on iOS Banuba Video Editor SDK has built in UI/UX experience and provides a number of customizations you can use to meet your requirements. **AVAILABLE:** :white_check_mark: Use your branded icons, colors, and text styles. [See details](ve-faq.md#i-want-to-use-custom-icons) :white_check_mark: Localize and change text resources. Default locale is :us: :white_check_mark: Make content you want i.e. a number of videos with different resolutions and durations, an audio file. [See details](guide_export.md) :white_check_mark: Masks and filters order. [See details](ve-faq.md#i-want-to-change-the-order-of-masks-video-effects-or-filters) **NOT AVAILABLE:** :x: Change layout or order of the screens after the entry point. Feel free to [request](https://www.banuba.com/support) custom UI/UX development. --- ## AI Clipping on iOS The [AI Clipping](https://www.banuba.com/ai-sdk) feature automates the video creation process by leveraging the power of artificial intelligence. The neural network transforms raw input into ready-to-post videos with various transitions, effects, and a precise music match. :::important The ```AI Clipping``` is based on the [Banuba Face AR SDK](https://www.banuba.com/facear-sdk/face-filters) product. Since this feature uses additional services, it is disabled by default. Please contact Banuba representatives to know more about using this feature. ::: Here is how users can interact with it: 1. User selects clips and music. People can choose their desired clips and accompanying music within the app. 2. AI trims the videos. The AI algorithm intelligently trims the selected clips to match the tempo and rhythm of the chosen track. 3. AI adds various effects. AI Clipping enhances the content by adding a variety of effects to create visually stunning content. 4. User exports, edits, or regenerates the clip. Upon completion, users have the flexibility to export the video as is, make further edits, or regenerate the clip for a fresh perspective. Regardless of the user’s editing skills, with the help of AI Clipping, everyone can get a stunning video within seconds. ## Supported Music Providers - [Banuba Music](guide_audio_content.md#connect-banuba-music) - [Soundstripe](guide_audio_content.md#connect-soundstripe)   ## Integration ### Setup configuration Add ```Banuba Face AR SDK``` dependency by following the [Face AR instruction](guide_far_arcloud.md#integrate-face-ar). Set up ```embeddingsDownloadUrl``` and ```musicProvider``` values in [VideoEditorModule](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/VideoEditorModule.swift#L73) :::important Contact Banuba representative to get trial keys for ```tracksURL``` and ```musicProvider``` ::: #### Config with Banuba Music provider ```swift let videoEditorConfig = VideoEditorConfig() videoEditorConfig.aiClippingConfiguration.embeddingsDownloadUrl = "https://d27n29bgbvbeer.cloudfront.net/index-staging.zip" videoEditorConfig.aiClippingConfiguration.musicProvider = .banubaMusic(tracksURL: URL(string: "https://d27n29bgbvbeer.cloudfront.net/response.json")!) ``` #### Config with Soundstripe provider ```swift let videoEditorConfig = VideoEditorConfig() videoEditorConfig.aiClippingConfiguration.embeddingsDownloadUrl = "..." videoEditorConfig.aiClippingConfiguration.musicProvider = .soundstripe(tracksURL: URL(string: "...")!) ``` ### Launch AI Clipping :::info Video creation with AI Clipping is available on Gallery screen by default. ::: For better experience we added new entry point ```.aiClipping``` to ```VideoEditorLaunchConfig``` for opening AI Clipping as separate mode. In this scenario the user starts from the gallery screen and is taken to AI Clipping screen after selecting media. ```swift let launchConfiguration = VideoEditorLaunchConfig( entryPoint: .aiClipping, hostController: self, animated: true ) videoEditorSDK.presentVideoEditor( withLaunchConfiguration: launchConfiguration, completion: nil ) ``` --- ## Closed Captions on iOS Closed captions(CC) are a textual representation of the audio within a media file. :::important The Close Captions feature is disabled by default. Please contact Banuba representatives to know more about using this feature. ::: Over 80% of videos played on mobile devices don’t have sound turned on. This means many forms of content (e.g. skits, monologues, educational clips, etc.) will be skipped if there are no subtitles. But making captions by hand is tedious. AI-generated subtitles solve this issue, as they are created and placed automatically. The users can then edit the text as well as change its style and color.       [AWS Transcribe service](https://docs.aws.amazon.com/transcribe/) is used to generate captions. ## Supported languages - Arabic - English - Mandarin - Spanish - Portuguese ## Integration Set up ```captionsUploadUrl```, ```captionsTranscribeUrl``` and ```apiKey``` values in the VideoEditorModule. ### Closed Captions V2 (Recommended) :::important Request API V2 key from Banuba representatives. ::: ```swift config.captionsConfiguration.apiV2Key = "..." ``` ### Closed Captions V1 :::important Request keys from Banuba representatives. ::: ```swift config.captionsConfiguration.captionsUploadUrl = "..." config.captionsConfiguration.captionsTranscribeUrl = "..." config.captionsConfiguration.apiKey = "..." ``` --- ## Audio content on iOS Guide to integrating and customizing audio providers in Video Editor SDK. ## Overview Audio content is the key part of making an awesome video. The Video Editor SDK can play, trim, merge and add audio content to a video. :::info 1. Banuba does not deliver audio content for the Video Editor SDK. 2. The Video Editor can apply audio files stored on the device. The SDK is not responsible for downloading audio content except for [Soundstripe](https://www.soundstripe.com/) and [Banuba Music](#connect-banuba-music). 3. Video Editor SDK supports only one music provider per launch. ::: There are 2 approaches to using audio content: 1. ```AudioBrowser``` - a specific module and set of screens that include the built-in support of browsing and applying audio content within the Video Editor. The user does not leave the SDK while using audio. 2. ```External API``` - the client implements a specific API for managing audio content. The user leaves the SDK and is taken to an app screen when audio is requested. ## Audio Browser Audio Browser is a specific iOS module that allows to browse, play and apply audio content within the Video Editor. It supports 3 sources for audio content: 1. ```Banuba Music``` - includes build in integration with Banuba Music, 2. ```Soundstripe``` - includes the built-in integration with the [Soundstripe](https://www.soundstripe.com/) API, 3. ```My Library``` - includes audio content available on the user's device. Add the dependency below into your [Podfile](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Podfile#L16) to integrate ```AudioBrowser```: ```swift pod 'BanubaAudioBrowserSDK', banuba_sdk_version ``` If you are using Swift Package Manager, please, visit the [SPM integration guide](./integration-ve.md#swift-package-manager). ## Connect Banuba Music Over 35 GB of royalty-free tracks available from within the Video Editor SDK. Your users could check them out through an inbuilt music browser and legally include them in their content. :::info The feature is not activated by default. Please contact Banuba representatives to know more about using this feature. :::   Use ```BanubaMusicProvider``` implementation in [VideoEditorModule](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/VideoEditorModule.swift#L81): ```Swift AudioBrowserConfig.shared.musicSource = .banubaMusic ``` ## Connect Soundstripe [Soundstripe](https://www.soundstripe.com/) is a service for providing the best audio tracks for creating video content. Your users will be able to add audio tracks while recording or editing video content. :::info The feature is not activated by default. Please, contact Banuba representatives to know more about using this feature. :::     Set the ```.soundstripe``` source in the ```AudioBrowserConfig``` configuration to enable ```Soundstripe```. For example, in [VideoEditorModule](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/VideoEditorModule.swift#L81): ```Swift AudioBrowserConfig.shared.musicSource = .soundstripe ``` ## Connect My Library ```My Library``` is a default implementation in ```AudioBrowser``` . It allows a user to apply audio that is available on the device. Set the ```.localStorageWithMyFiles``` source in the ```AudioBrowserConfig``` configuration to enable ```My Library```. For example, in [VideoEditorModule](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/VideoEditorModule.swift#L100): ```Swift AudioBrowserConfig.shared.musicSource = .localStorageWithMyFiles ``` ## Connect External API The Video Editor includes a special API for integrating your custom audio content provider and applying this content to the Video Editor. The user will be taken to your app's specific screen when audio is requested on the Video Editor screen i.e. the camera or editor. Next, once the user picks audio content on your app screen, you need to follow API and return the user to the Video Editor. Any audio file should be stored on the device before applying. To pass audio content to the Video Editor you need to implement a factory that conforms to the `MusicEditorExternalViewControllerFactory` protocol. And put it to the `musicEditorFactory` property in `ExternalViewControllerFactory`. Your factory should implement the following methods: ```swift protocol MusicEditorExternalViewControllerFactory: AnyObject { /// contoller which will be used for presenting otherwise makeTrackSelectionViewController will be used var audioBrowserController: TrackSelectionViewController? { get set } /// should returns controller which provides audio content for Video Editor SDK /// - selectedAudioItem is currently selected audio item func makeTrackSelectionViewController(selectedAudioItem: AudioItem?) -> TrackSelectionViewController? /// should returns controller which provides effects audio content for Video Editor SDK /// Note: MainMusicViewControllerConfig should contains editButton with type .effect func makeEffectSelectionViewController(selectedAudioItem: AudioItem?) -> EffectSelectionViewController? /// should returns view for countdown animation in record button at music editor func makeRecorderCountdownAnimatableView() -> MusicEditorCountdownAnimatableView? } ``` where `AudioItem` is an entity which includes information about the selected audio item in the Video Editor: ```swift // MARK: - AudioItem protocol protocol AudioItem { var uuid: UUID { get } var url: URL { get } var coverURL: URL? { get } var title: String? { get set } var additionalTitle: String? { get set } /// True - display track with which the video was recorded and allow users to edit it. /// False - track will be playing but not displayed. var isEditable: Bool { get set } } ``` Your custom audio browser implementation should conform to the `TrackSelectionViewController` protocol: ```swift class YourCustomAudioBrowser: UIViewController, TrackSelectionViewController { weak var trackSelectionDelegate: TrackSelectionViewControllerDelegate? } ``` Using `trackSelectionDelegate` you can notify the Video Editor about actions in the audio browser with the following methods: ```swift protocol TrackSelectionViewControllerDelegate: AnyObject { func trackSelectionViewController( viewController: TrackSelectionViewController, didSelectFile url: URL, coverURL: URL?, timeRange: CMTimeRange?, isEditable: Bool, title: String, additionalTitle: String?, uuid: UUID ) func trackSelectionViewControllerDidCancel( viewController: TrackSelectionViewController ) func trackSelectionViewControllerDiscardCurrentTrack( viewController: TrackSelectionViewController ) } ``` ## Connect Apple Music You can pass music from Apple Music to the Video Editor SDK. You should export media to a temporary directory and then pass the music url to the Video Editor SDK using `trackSelectionDelegate`. In this sample, we show how to implement it: ```swift let asset = AVURLAsset(url: url) let destination = FileManager.default .temporaryDirectory .appendingPathComponent("\(NSUUID().uuidString).caf") let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetPassthrough) exportSession?.outputURL = destination exportSession?.outputFileType = AVFileType.caf exportSession?.exportAsynchronously() { if let error = exportSession?.error { completion(nil, error as NSError) } else { completion(destination, nil) } } ``` To present your custom audio browser in the Video Editor you need to set the created `ExternalViewControllerFactory` to [externalViewControllerFactory](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/VideoEditorModule.swift#L29). --- ## Camera screen on iOS Guide to modifying camera UI elements and screen configuration. ## Change icons You can use your app specific icons in Video Editor SDK. Add icon files to Xcode ```Assets``` folder with predefined names.   To add custom icons, use the ```AdditionalEffectsButtonConfiguration``` within ```RecorderConfiguration```, ```TimerConfiguration``` and ```SpeedBarButtonsConfiguration```. Refer to the configuration below. To exclude any button, just don't include it in the ```additionalEffectsButtons``` array. ```swift var config = VideoEditorConfig() config.recorderConfiguration.additionalEffectsButtons = [ AdditionalEffectsButtonConfiguration( identifier: .toggle, imageConfiguration: ImageConfiguration(imageName:"toggle.png"), selectedImageConfiguration: ImageConfiguration(imageName: "toggleSelected.png") ), AdditionalEffectsButtonConfiguration( identifier: .flashlight, imageConfiguration: ImageConfiguration(imageName:"flashlight.png"), selectedImageConfiguration: ImageConfiguration(imageName:"flashlightSelected.png") ), AdditionalEffectsButtonConfiguration( identifier: .speed, imageConfiguration: ImageConfiguration(imageName:"speed.png"), selectedImageConfiguration: ImageConfiguration(imageName: "speedSelected.png") ), AdditionalEffectsButtonConfiguration( identifier: .sound, imageConfiguration: ImageConfiguration(imageName:"sound.png"), selectedImageConfiguration: ImageConfiguration(imageName: "soundSelected.png") ), AdditionalEffectsButtonConfiguration( identifier: .muteSound, imageConfiguration: ImageConfiguration(imageName:"muteSound.png"), selectedImageConfiguration: ImageConfiguration(imageName:"muteSoundSelected.png") ), AdditionalEffectsButtonConfiguration( identifier: .pip, imageConfiguration: ImageConfiguration(imageName:"pip.png"), selectedImageConfiguration: ImageConfiguration(imageName:"pipSelected.png") ), AdditionalEffectsButtonConfiguration( identifier: .beauty, imageConfiguration: ImageConfiguration(imageName:"beauty.png"), selectedImageConfiguration: ImageConfiguration(imageName: "beautySelected.png") ), AdditionalEffectsButtonConfiguration( identifier: .effects, imageConfiguration: ImageConfiguration(imageName:"effects.png"), selectedImageConfiguration: ImageConfiguration(imageName:"effectsSelected.png") ), AdditionalEffectsButtonConfiguration( identifier: .masks, imageConfiguration: ImageConfiguration(imageName:"masks.png"), selectedImageConfiguration: ImageConfiguration(imageName: "masksSelected.png") ), AdditionalEffectsButtonConfiguration( identifier: .timer, imageConfiguration: ImageConfiguration(imageName:"timer.png"), selectedImageConfiguration: ImageConfiguration(imageName: "timerSelected.png") ) ] config.recorderConfiguration.timerConfiguration.defaultButton = ImageButtonConfiguration( imageConfiguration: ImageConfiguration(imageName:"timer.png") ) config.recorderConfiguration.speedBarButtons = SpeedBarButtonsConfiguration( imageHalf: ImageConfiguration(imageName:"imageHalf.png"), imageNormal: ImageConfiguration(imageName:"imageNormal.png"), imageDouble: ImageConfiguration(imageName:"imageDouble.png"), imageTriple: ImageConfiguration(imageName:"imageTriple.png"), selectedTitleColor: UIColor, titleColor: UIColor, backgroundColor: UIColor, cornerRadius: CGFloat ) ``` --- ## Camera Layouts on iOS Camera Layouts is a set of camera recording layouts that combine the camera feed with additional content in a single video. Users can choose from the following options: - **Blur** — Softens the background to keep the subject in focus. - **Custom color** — Replaces the background with any solid color. - **Media** — Uses an image or a video file as the background. - **Weatherman** — Places the user over the background media, the way a TV presenter is shown. - **Picture in Picture** — Combines the camera with a second video side by side or as an insert. This feature replaces the previous `Green Screen`, `Weatherman` and `PIP` features. All of them are now included under Camera Layouts.   :::important The feature requires the Face AR product with Background Segmentation feature enabled. Without Background Segmentation, the background replacement layouts will not appear or function. Contact Banuba representatives to enable it ::: :::warning Layouts are gated per group: PiP layouts require the PiP feature, weatherman layouts require the weatherman feature, and blur / green screen layouts require background separation together with Face AR. Layouts that the license does not cover are hidden from the panel. ::: Camera Layouts replaces the standalone `PIP` screen used before `1.54.2`. All PiP modes are still available, they are now selected from the `Layouts` panel on the camera screen. The multi-layer recording effect is perfect for reaction videos, slideshows, product demos, and more. This feature is similar to the TikTok duet feature. The subsequent guide explains how to start and customize `Camera Layouts`. ## Supported layouts Layouts are grouped into two modes on the camera screen: `Solo`, where the user is separated from the background, and `Spotlight`, where the camera is combined with a second video. | `CameraLayout` | Mode | Payload | Description | | ------------- |:-------------:|:-------------:| :------------- | | `blur` | Solo | not required | blurred background behind the user | `greenScreen` | Solo | `.color(UIColor)` | solid color background, green by default | `greenScreenWithMedia` | Solo | `.media(URL)` | image or video as the background | `weathermanTopLeft` | Spotlight | `.media(URL)` | user in the top left corner over the media | `weathermanBottomLeft` | Spotlight | `.media(URL)` | user in the bottom left corner over the media | `weathermanCenter` | Spotlight | `.media(URL)` | user in the center over the media | `pipCircleBottom` | Spotlight | `.media(URL)` | circle camera insert over the video | `pipRectangleBottom` | Spotlight | `.media(URL)` | rectangle camera insert over the video | `pipBottom` | Spotlight | `.media(URL)` | video and camera split horizontally | `pipLeft` | Spotlight | `.media(URL)` | video and camera split vertically | `pipTwoThirdBottom` | Spotlight | `.media(URL)` | video on top two thirds, camera below When the user picks a `Spotlight` layout or `greenScreenWithMedia` and no media has been selected yet, the gallery opens automatically: PiP layouts ask for a video, the other layouts accept a video or an image. The selected media is kept while the user switches between layouts. ## Opening the camera with a preselected layout Create `VideoEditorLaunchConfig` in [ExampleViewController](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/ExampleViewController.swift#L55) and provide the layout along with its media: ```swift let launchConfig = VideoEditorLaunchConfig( entryPoint: .camera, hostController: self, // highlight-add-start cameraLayout: VideoEditorLaunchConfig.CameraLayoutConfig( layout: .pipCircleBottom, payload: .media(resultUrls[.zero]) ), // highlight-add-end animated: true ) self.presentVideoEditor(with: launchConfig) ``` `CameraLayoutConfig` is a failable initializer. Every layout except `.blur` and `.greenScreen` requires `.media(URL)`, otherwise the initializer returns `nil` and the camera opens with the default layout. `.blur` ignores the payload and accepts `.none`, `.greenScreen` accepts `.color(UIColor)` and falls back to green when another payload is passed. ```swift // no media required let blur = VideoEditorLaunchConfig.CameraLayoutConfig(layout: .blur, payload: .none) let color = VideoEditorLaunchConfig.CameraLayoutConfig(layout: .greenScreen, payload: .color(.systemPink)) ``` The preselected layout is applied once the camera pipeline has started and the camera is switched to the front one. `cameraLayout` is ignored for the `editor` and `trimmer` entry points. ## Customizing the entry point The `Layouts` panel is opened with the layouts button in the camera controls. Use `AdditionalEffectsButtonConfiguration` with the `.layouts` identifier to restyle it: ```swift var config = VideoEditorConfig() config.recorderConfiguration.additionalEffectsButtons = [ AdditionalEffectsButtonConfiguration( identifier: .layouts, imageConfiguration: ImageConfiguration(imageName: "camera_control.layouts"), selectedImageConfiguration: ImageConfiguration(imageName: "camera_control.layouts"), title: TextButtonConfiguration(style: makeTextStyle(), text: "Layouts"), titlePosition: .left, width: 120, height: 36.0 ), ... ] ``` Camera controls are laid out in the order of the `additionalEffectsButtons` array. Remove the `.layouts` configuration from the array to hide the feature completely. In photo mode the layouts button is shown only when the license covers background separation or weatherman layouts. ## Migrating from `PIP` `pipVideoItem` is removed in `1.54.2`. Pass the same video in `cameraLayout` and specify the layout that used to be selected on the `PIP` settings screen: ```swift let launchConfig = VideoEditorLaunchConfig( entryPoint: entryPoint, hostController: self, videoItems: resultUrls, // highlight-remove-next-line pipVideoItem: resultUrls[.zero], // highlight-add-start cameraLayout: VideoEditorLaunchConfig.CameraLayoutConfig( layout: .pipCircleBottom, payload: .media(resultUrls[.zero]) ), // highlight-add-end animated: true ) ``` Note that `videoItems` is no longer needed to start the feature: with the `camera` entry point the layout media is taken from `cameraLayout` only. The old `PIP` modes map to `CameraLayout` as follows: | `PIP` mode | `CameraLayout` | | ------------- | :------------- | | `.react` | `pipCircleBottom` for the round camera insert, `pipRectangleBottom` for the rectangle one | `.topBottom` | `pipBottom` for the equal split, `pipTwoThirdBottom` for the two thirds split | `.leftRight` | `pipLeft` | `.floating` | not available, use `pipCircleBottom` or `pipRectangleBottom` `PIPSettingsConfiguration.layoutSettingsButtonsConfiguration` and `PIPSelectableCellConfiguration` were removed earlier, in `1.53.1`, together with the standalone `PIP` settings screen. The set of layouts is no longer configurable: the panel shows every layout the license covers. Styling of the entry point is done with the `.layouts` button configuration described above. --- ## Cover image on iOS Cover image screen allows users to pick any frame of video as image or choose an image from gallery. This screen can be turned on or off by changing the `isVideoCoverSelectionEnabled` field of `FeatureConfiguration`: ```swift let config = VideoEditorConfig() config.featureConfiguration.isVideoCoverSelectionEnabled = false ``` To change the UI elements of the screen (icons, colors, etc.), please, modify the default values of `VideoCoverSelectionConfiguration`: ```swift let config = VideoEditorConfig() config.extendedVideoCoverSelectionConfiguration.doneButton.textConfiguration?.color = UIColor.red ``` You can override the following string resources in your app: | Key | Default value | | ------------- | ----------- | | Choose Cover Screen Name | Thumbnail | | cover.thumbnail.title | Choose a thumbnail | | cover.gallery.button.title | Choose from Gallery | | cover.delete.button.title | Delete | | Cancel | Cancel | | Done | Done | --- ## Drafts screen on iOS Guide to integrating and customizing drafts screen on Video Editor SDK. ## Configuration Drafts are enabled by default, asks the user to save a draft before leave any VideoEditor screen. If you need to change drafts configuration you should add the code below in the [VideoEditorModule](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/VideoEditorModule.swift#L83): ```swift var config = VideoEditorConfig() config.featureConfiguration.draftsConfig = .enabled ``` You can choose one of these options: - ```.enabled``` - drafts enabled, asks the user to save a draft - ```.enabledSaveToDraftsByDefault``` - drafts enabled, saved by default without asking the user - ```.enabledAskIfSaveNotExport``` - drafts enabled, asks the user to save a draft without export - ```.disabled``` - disabled drafts The default value is ```.enabled``` ## Draft Service The `DraftsService` class is used for managing drafts: ```swift /// External Draft of video session typealias ExternalDraft = VideoSequence /// Allows you to manage drafts class DraftsService { /// Get drafted video sequences func getDrafts() -> [ExternalDraft] /// Remove specific video sequence /// - parameters: /// - externalDraft: Drafted video sequence func removeExternalDraft(_ externalDraft: ExternalDraft) -> Bool /// Get preview for specific drafted video sequence /// - parameters: /// - externalDraft: Drafted video sequence /// - thumbnailHeight: Preview height /// - completion: Completion when preview UIImage generated func getPreviewForVideoSequence( _ externalDraft: ExternalDraft, thumbnailHeight: CGFloat, completion: ((_ preview: UIImage?) -> Void)? ) } ``` To get the instance of `DraftsService` use the `BanubaVideoEditor` instance. ***Example of usage:*** ```swift let videoEditorSDK = BanubaVideoEditor(...) // Initialization of main entity let drafts = videoEditorSDK?.draftsService.getDrafts() // Get drafts list let draft = drafts.first! // Get draft preview videoEditorSDK?.draftsService.getPreviewForVideoSequence( // Choosen draft from list of drafts draft, // Default config, where config is VideoEditorConfig instance thumbnailHeight: config.videoResolutionConfiguration.currentThumbnailHeight, completion: { preview in // Preview usage } ) // Remove draft and use returned value to your own condition usage if needed let _ = videoEditorSDK?.draftsService.removeVideoSequence(videoSequence) // Open Video Editor with preselected draft let draftedConfig = VideoEditorLaunchConfig.DraftedLaunchConfig( // Choosen draft from list of drafts externalDraft: draft, // Any case from DraftsFeatureConfig entity draftsConfig: .enabled ) let config = VideoEditorLaunchConfig( entryPoint: .editor, hostController: self, draftedLaunchConfig: draftedConfig, animated: true ) // Present Video Editor self.videoEditorSDK?.presentVideoEditor( withLaunchConfiguration: config, completion: nil ) ``` ## Transferring drafts BanubaVideoEditor supports archiving drafts into a zip file. It may help you with backing up user data to the server or sharing video content across the devices. For exporting and importing `BanubaVideoEditor` has the following methods: ```swift /// Archive and compress external draft into zip file. /// Returns URL to archive /// Discussion: After performing all actions with zip file your are responsible to remove archive file. func exportExternalDraft(_ externalDraft: ExternalDraft) throws -> URL /// Unarchive ExternalDraft from zip file func importExternalDraft(fromZipUrl url: URL) throws -> ExternalDraft ``` ***Example of usage:*** ```swift let videoEditorSDK = BanubaVideoEditor(...) // Initialization of main entity let drafts = videoEditorSDK?.draftsService.getDrafts() // Get drafts list let draft = drafts.first! // Make archive from draft let archiveURL = try? videoEditorSDK?.exportExternalDraft(draft) // Import draft from archive let importedDraft = try! videoEditorSDK?.importExternalDraft(fromZipUrl: archiveURL) // Open Video Editor with unarchived draft let draftedConfig = VideoEditorLaunchConfig.DraftedLaunchConfig( externalDraft: importedDraft, draftsConfig: .enabled ) let config = VideoEditorLaunchConfig( entryPoint: .editor, hostController: self, draftedLaunchConfig: draftedConfig, animated: true ) self.videoEditorSDK?.presentVideoEditor( withLaunchConfiguration: config, completion: nil ) ``` --- ## Editor screen on iOS Guide to integrating and customizing Editor screen. ## Change icons You can use your app specific icons in Video Editor SDK. Add icon files to Xcode ```Assets``` folder with predefined names.   To add custom icons, use the ```AdditionalEffectsButtonConfiguration``` within ```EditorConfiguration```. Refer to the configuration below. To exclude any button, just don't include it in the ```additionalEffectsButtons``` array. ```swift var config = VideoEditorConfig() config.editorConfiguration.additionalEffectsButtons = [ AdditionalEffectsButtonConfiguration( identifier: .sticker, imageConfiguration: ImageConfiguration(imageName: "stickers"), selectedImageConfiguration: ImageConfiguration(imageName: "stickersSelected") ), AdditionalEffectsButtonConfiguration( identifier: .text, imageConfiguration: ImageConfiguration(imageName: "text"), selectedImageConfiguration: ImageConfiguration(imageName: "textSelected") ), AdditionalEffectsButtonConfiguration( identifier: .captions, imageConfiguration: ImageConfiguration(imageName: "captions"), selectedImageConfiguration: ImageConfiguration(imageName: "captionsSelected") ), AdditionalEffectsButtonConfiguration( identifier: .effects, imageConfiguration: ImageConfiguration(imageName: "effects"), selectedImageConfiguration: ImageConfiguration(imageName: "effectsSelected") ), AdditionalEffectsButtonConfiguration( identifier: .masks, imageConfiguration: ImageConfiguration(imageName: "masks"), selectedImageConfiguration: ImageConfiguration(imageName: "masksSelected") ), AdditionalEffectsButtonConfiguration( identifier: .sound, imageConfiguration: ImageConfiguration(imageName: "music"), selectedImageConfiguration: ImageConfiguration(imageName: "musicSelected") ), AdditionalEffectsButtonConfiguration( identifier: .time, imageConfiguration: ImageConfiguration(imageName: "time"), selectedImageConfiguration: ImageConfiguration(imageName: "timeSelected") ), AdditionalEffectsButtonConfiguration( identifier: .color, imageConfiguration: ImageConfiguration(imageName: "filters"), selectedImageConfiguration: ImageConfiguration(imageName: "filtersSelected") ), AdditionalEffectsButtonConfiguration( identifier: .blur, imageConfiguration: ImageConfiguration(imageName: "blur"), selectedImageConfiguration: ImageConfiguration(imageName: "blurSelected") ), AdditionalEffectsButtonConfiguration( identifier: .autoCut, imageConfiguration: ImageConfiguration(imageName: "autocut"), selectedImageConfiguration: ImageConfiguration(imageName: "autocutSelected") ) ] ``` --- ## NEW Editor screen on iOS Guide to integrating and customizing New Editor screen. ## Overview With the new interface, better controls, and additional quality of life improvements, making stunning videos is easier and more fun than ever. Design and user experience principles are constantly evolving. To keep up with the latest developments and best practices, our team has completely redesigned the Video Editor SDK to be as convenient and enjoyable as possible.       ## Integration Init the Video Editor with argument ```[.useEditorV2: true]``` to enable ```Editor UI V2```: ```swift let videoEditorSDK = BanubaVideoEditor( token: token, arguments: [.useEditorV2: true], configuration: createConfiguration() ) ``` --- ## Export media on iOS Video Editor SDK allows to export a number of media files i.e. video and audio with various resolutions and other configurations. Video is exported as ```.mp4``` file. :::warning Export is a very heavy computational task that takes time and the user has to wait for it to be done. The execution time depends on: 1. the video duration - the longer the video, the longer the execution time; 2. a number of video sources - the more sources, the longer the execution time; 3. a number of effects and their usage in the video - the more effects and the bigger their usage, the longer the execution time; 4. a number of the exported videos - the more videos and audios you want to export, the longer the execution time; 5. the device hardware - the most powerful devices can execute export much quicker. ::: Export only supports the ` Foreground` mode where the user has to wait on the progress screen until the processing is done. The ` Background` export is not allowed on iOS due to the [iOS Restrictions](https://developer.apple.com/documentation/metal/gpu_devices_and_work_submission/preparing_your_metal_app_to_run_in_the_background) Here is a screen that is shown in the ` Foreground` mode: ## Video codecs The Video Editor supports the following video codec options: 1. ` HEVC` - H265 codec. ` Default` if the device supports this codec; 2. ` AVC_PROFILES` - H264 codec with High Profile. You can change the video codec for export by using the ` ExportVideoConfiguration.useHEVCCodecIfPossible` property. In this example, the H264 is set in [VideoEditorModule](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/VideoEditorModule.swift#L56): ```diff let exportConfiguration = ExportVideoConfiguration( fileURL: destFile, quality: .auto, // highlight-add-next-line + useHEVCCodecIfPossible: false, watermarkConfiguration: watermarkConfiguration ) ``` ## Video quality | 360p(360x640) | 480p(480x854) | QHD540(540x960) | HD(720x1280) | FHD(1080x1920) | QHD(1440x2560) | UHD(2160x3840) | |----|---------------|-----------------|--------------|----------------|----------------|----------------| | 1000 kb/s | 2500 kb/s | 3000 kb/s | 5000 kb/s | 8000 kb/s | 16000 kb/s | 36000 kb/s | The Video Editor has the built-in feature for detecting device performance capabilities and finding optimal video quality params for export. You can provide a custom video resolution for the exported video by using the ` ExportVideoConfiguration.quality` property: ```diff let hdExportConfiguration = ExportVideoConfiguration( fileURL: destFile, // highlight-add-next-line + quality: .videoConfiguration(ExportVideoInfo(resolution: .hd1280x720, useHEVCCodecIfPossible: true)), useHEVCCodecIfPossible: true, watermarkConfiguration: watermarkConfiguration ) ``` ## Export storage The Video Editor export method requires the file destination where the exported video will be stored. First, create the destination file: ```swift let manager = FileManager.default let destFile = manager.temporaryDirectory.appendingPathComponent("tmp.mov") ``` and use it in ` ExportVideoConfiguration`: ```diff let hdExportConfiguration = ExportVideoConfiguration( // highlight-add-next-line + fileURL: destFile, quality: .videoConfiguration(ExportVideoInfo(resolution: .hd1280x720, useHEVCCodecIfPossible: true)), useHEVCCodecIfPossible: true, watermarkConfiguration: watermarkConfiguration ) ``` ## Implement the export flow You can create your own flow for exporting media files for your application. Use ` ExportConfiguration` to create an instance with the configurations that meet your product requirements. Below there is a sample that exports 2 video files: 1. a video with the auto resolution **without** a watermark; 2. a video with the HD resolution **with** a watermark: ```Swift let watermarkConfiguration = WatermarkConfiguration( watermark: ImageConfiguration(imageName: "Common.Banuba.Watermark"), size: CGSize(width: 204, height: 52), sharedOffset: 20, position: .rightBottom ) let autoExportConfiguration = ExportVideoConfiguration( fileURL: destFile1, quality: .auto, useHEVCCodecIfPossible: true, watermarkConfiguration: nil ) let hdExportConfiguration = ExportVideoConfiguration( fileURL: destFile2, quality: .videoConfiguration(ExportVideoInfo(resolution: .hd1280x720, useHEVCCodecIfPossible: true)), useHEVCCodecIfPossible: true, watermarkConfiguration: watermarkConfiguration ) let exportConfig = ExportConfiguration( videoConfigurations: [autoExportConfiguration, hdExportConfiguration], isCoverEnabled: true, gifSettings: nil ) ``` Use the created ` ExportConfiguration` to start the export by using the ` BanubaVideoEditor.export()` method: ```Swift public func export( using configuration: ExportConfiguration, exportProgress: ((TimeInterval) -> Void)?, completion: @escaping ((_ error: Error?, _ exportCoverImages: ExportCoverImages?) -> Void) ) ``` ## Handle the export result The ` BanubaVideoEditor.export()` method allows to start the export and track the result. Provide: 1. ` ExportConfiguration` - where you set up all the required media content you want to make; 2. ` exportProgress` - a callback that gets called when the export progress changes. Values are 0.0-1.0; 3. ` completion` - a callback that gets called when the export is finished with an error or not: ```swift videoEditorSDK?.export( using: exportConfiguration, exportProgress: { progress in DispatchQueue.main.async { // Export is in progress. You can show progress view. Progress is 0.0 - 1.0 ... } }, completion: { [weak self] error, exportCoverImages in DispatchQueue.main.async { // Export finishes. Use 'error' value to detect the state of export. // Hide progress view // You can clear exported session if you do no need it anymore //self?.videoEditorSDK?.clearSessionData() } ``` :::tip If the export is finished successfully, you can use the instance of ` ExportConfiguration` as a result and access the media files and its metadata. ::: ## Add a watermark :::warning A watermark is not added to the exported video by default. ::: You can use your custom watermark for a video. First, create the instance of ` WatermarkConfiguration` to ```swift let watermarkConfiguration = WatermarkConfiguration( watermark: ImageConfiguration(imageName: "Common.Banuba.Watermark"), size: CGSize(width: 204, height: 52), sharedOffset: 20, position: .rightBottom ) ``` where ` position` is used for locating the watermark image in a video: ```swfit public enum WatermarkPosition { case leftTop case leftBottom case rightTop case rightBottom } ``` Next, set ` watermarkConfiguration` to every instance of ` ExportVideoConfiguration` where you want to add a watermark in [VideoEditorModule](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/VideoEditorModule.swift#L57): ```diff let hdExportConfiguration = ExportVideoConfiguration( fileURL: destFile, quality: .hd1280x720, useHEVCCodecIfPossible: true, // highlight-add-next-line + watermarkConfiguration: watermarkConfiguration ) ``` ## Export the GIF preview The Video Editor allows to export a preview of the video as a GIF file. The instance of ` GifSettings` is required in ` ExportConfiguration` to export a preview during the export. You can specify this property in [VideoEditorModule](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/VideoEditorModule.swift#L63): ```diff let exportConfig = ExportConfiguration( videoConfigurations: [exportConfiguration], isCoverEnabled: true, // highlight-add-next-line + gifSettings: GifSettings(duration: 0.3) ) ``` ## Get the audio track of exported video You can get the video's audio track after its successfull export using the `BanubaVideoEditor.exportAudio()` method: ```Swift public func exportAudio( fileUrl: URL, audioSettings: [String: Any] = VESettings.audio, completion: @escaping (Bool, Error?) -> Void ) ``` :::tip Learn about the available options on the [Apple Developer Portal](https://developer.apple.com/documentation/avfoundation/audio_settings) to provide custom audio quality settings. ::: ## Get the information about the music tracks used during creation of exported video You can use the `musicMetadata` property of `BanubaVideoEditor` class to get the array of `MusicEditorTrack` entities containing the information about the corresponding music tracks. ```swift /// Video Editor main entity and entry point. /// Can present and hide root view controller. /// Has default export method. public class BanubaVideoEditor { /// Simple metadata of music composition settings public var musicMetadata: MusicEditorMetadata? { get } ... } ``` ```swift // MARK: - MusicEditorTrack public struct MusicEditorTrack: Codable { ///Track URL public var url: URL ///Track original URL public var originalURL: URL ///Track title public var title: String ///Track id public var id: Int32 /// Track volume public var volume: Float ... } ``` ## Export metadata analytics While exporting media content, the Video Editor generates simple metadata analytics that you can use to analyze what media content your users make. Metadata is a JSON string and can be received once the export is finished successfully: ```swift let metadataJson: String? = videoEditorSDK?.metadata?.analyticsMetadataJSON ``` The JSON sample: ```json { "export_success": true, // defines if the export finished succesffully "aspect_ratio": "original", // aspect ration used in exported video "video_resolutions": ["1080x1920"], // list of video resolutions used in export "camera_effects": [], // list of effects of features used on camera screen while recording video "ppt_effects": { "visual": 2, // num of visual effects i.e. Glitch, VHS used in exported video "speed": 1, // num of speed effects used in exported video "mask": 6, // num of AR masks used in exported video "color": 3, // num of color effects used in exported video "text": 1, // num of text effects used in exported video "sticker": 1, // num of sticker effects used in exported video "blur": 1 // num of blur effects used in exported video }, "sources": { "camera": 0, // num of video sources recorded on camera screen(not PIP) "gallery": 1, // num of video sources selected in the gallery "pip": 0, // num of video recorded with PIP "slideshow": 0, // num of video exported as slideshow "audio": 0 // num of audi tracks }, "export_duration": 12.645, // export processing duration "video_duration": 20.11, // exported video duration "video_count": 1, // num of exported video files "os_version": "11", // OS version "sdk_version": "1.26.6" // VE SDK version } ``` --- ## Face AR and AR Cloud products on iOS [Banuba Face AR SDK](https://www.banuba.com/facear-sdk/face-filters) product is used on camera and editor screens for applying various AR effects while making video content. ## Overview Any Face AR effect is a folder that includes a number of files required for the Face AR SDK to play this effect. :::warning Make sure every effect folder includes the ` preview.png` file. This file is used as a preview for the AR effect. ::: ## Integrate Face AR :::info ```Banuba Face AR SDK``` integration is included in the [Github sample](https://github.com/Banuba/ve-sdk-ios-integration-sample/). ::: Add the dependency below to the [Podfile](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Podfile#L19) to integrate `Banuba Face AR SDK` into your project: ```ruby pod 'BanubaSDK', '1.52.1' ``` ## Manage effects There are 2 options for managing AR effects: 1. ` bundleEffects` folder - use [bundleEffects](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/bundleEffects) folder, 2. ` AR Cloud` Effects - which are stored on the remote server. :::warning Please, keep the name ` bundleEffects`, otherwise, the app will not start. Create the `bundleEffects` folder if it does not exist. ::: :::tip You can use both options i.e. store just a few AR effects in `bundleEffects` and 100 or more AR effects on `AR Cloud`. ::: ## Integrate AR Cloud `AR Cloud` is a cloud solution for storing the Banuba Face AR effects on the server and is used by the Face AR and Video Editor products. Any AR effect downloaded from `AR Cloud` is cached on the user's device. Add the dependency below to the [Podfile](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Podfile#L11) to integrate `AR Cloud` into your project: ```ruby pod 'BanubaARCloudSDK', '1.52.1' ``` Since the link to your AR Cloud bucket is included into the license token, AR effects will appear once you set the license token with the AR Cloud link. ## Change the effects order By default, all AR effects are listed in alphabetical order. AR effects from `bundleEffects` are listed in the beginning. Provide your ordered list of effects to `preferredMasksOrder` in `VideoEditorConfig`: ```swift videoEditorConfig.recorderConfiguration.recorderEffectsConfiguration.preferredMasksOrder = [ "XYScanner", "Background" ... ] ``` :::warning These are the names of specific directories located in `bundleEffects` or on `AR Cloud`. ::: ## Disable Face AR SDK The Video Editor SDK can work without the Face AR SDK. Change the [Podfile](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Podfile) to disable the Face AR SDK: ```diff banuba_sdk_version = '1.52.1' // highlight-remove-start - pod 'BanubaSDK', banuba_sdk_version // highlight-remove-end // highlight-add-next-line + pod 'BanubaSDKSimple', banuba_sdk_version ``` :::tip Please, keep in mind that you can remove all AR effects from [bundleEffects](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/bundleEffects) if your license does not include the Face AR product. ::: --- ## Drawing on iOS Lets your users draw freely on screen. It is a convenient tool for highlighting important objects in the video or spicing up the frame with funny doodles or stylish art. There are 5 line variants to choose from for more self-expression opportunities. :::important The Drawing feature is disabled by default. Please contact Banuba representatives to know more about using this feature. :::       --- ## Gallery screen on iOS Video Editor SDK includes built in gallery functionality where the user can pick any video or image and use it while making video. :::info The Gallery screen is integrated by default. ::: ## Customizations The gallery is used in the app when you want to select a photo or video stored on your phone. Implement ` GalleryConfiguration` and set it to ` VideoEditorConfig.combinedGalleryConfiguration` to customize the gallery screen. To setup the visible tabs for the gallery, just configure it in the `CombinedGalleryConfiguration` entity: ```swift var config = VideoEditorConfig() config.combinedGalleryConfiguration.visibleTabsInGallery = [.video, .photo] ``` ## Implement a custom gallery Please, follow these steps to integrate your gallery into the SDK: ### Step 1 Implement custom `UIViewController` inherited from `GalleryViewController`: ```swift @objc open class GalleryViewController: UIViewController { open weak var delegate: GalleryViewControllerDelegate? open var configuration: GalleryConfiguration? open var selectionBehaviour: GallerySelectionBehaviour? /// Setups new album at gallery open func useAlbum(_ albumModel: AlbumModel) {} /// Cancel current export open func cancelExport() {} /// Retry export failed items open func retryExport() {} } ``` - `delegate`- use this property to notify the Video Editor SDK about the user's actions in the custom gallery. Below there is a list of possible actions: ```swift // MARK: - GalleryViewControllerDelegate @objc public protocol GalleryViewControllerDelegate: AnyObject { /// Tells delegate object about starting asynchronous operations at the gallery. /// BanubaVideoEditorSDK showing full-screen spinner by this event. It can help to prevent unnecessary actions from a user. func galleryViewController(_ controller: GalleryViewController, didStartExportWith progressHandler: ProgressHandler) /// Tells delegate object about finishing asynchronous operations at the gallery func galleryViewController(_ controller: GalleryViewController, didEndExportWith error: Error?, hideProgressViewCompletion: @escaping () -> Void) /// Tells delegate object about the closing gallery. func galleryViewControllerDidClose(_ controller: GalleryViewController) /// Tells delegate object about completion picking gallery items. func galleryViewControllerDone( _ controller: GalleryViewController, withGalleryItems items: [GalleryItem] ) /// Tells delegate object that he should present message. /// In BanubaVideoEditorSDK it presents popup message. func galleryViewController( _ controller: GalleryViewController, presentMessage message: String ) } ``` - `configuration` - contains the UI configuration. All the details you can find [here](#customizations); - `selectionBehaviour` - contains the gallery settings. ```swift /// Setups gallery selection behaviour @objc public class GallerySelectionBehaviour: NSObject { /// Maximum possible selected gallery items quantity which can select a user. public let maximumSelectedCount: Int /// Setups already selected items quantity if gallery open as a picker at trimmer sceen or other cases. /// Use this field to control maximum selection items. public let selectedItemsCount: Int? /// Setups picker mode if isMultiselectModeEnabled is false. /// Otherwise, multiselection mode enabled. public let isMultiselectModeEnabled: Bool /// Setups gallery video duration fetched from user gallery supported by BanubaVideoEditorSDK. /// By default is 3.0 public let minimumGalleryVideoDuration: TimeInterval /// Setups allowed media types which user can select in gallery public let allowedMediaTypes: [GalleryMediaType] } @objc public enum GalleryMediaType: Int, CaseIterable { case video case photo } ``` `GalleryItem` is a protocol to which your items should conform in order to pass the gallery selection result to `BanubaVideoEditorSDK`: ```swift @objc public protocol GalleryItem: NSObjectProtocol { /// Video representation url asset var urlAsset: AVURLAsset? { get } /// Preview for gallery item var preview: UIImage? { get set } /// GalleryItem duration var duration: TimeInterval { get } /// Type can be video, photo or unknown var type: GalleryItemType { get } /// Requests preview for displaying in gallery list func requestPreview( size: CGSize, handler: @escaping (UIImage?) -> Void ) /// Requests photo with desired size func requestPhoto( size: CGSize, progressHandler: ((Double) -> (Bool))?, handler: @escaping (UIImage?, Error?) -> Void ) /// Requests video url asset func requestAVURLAsset( progressHandler:((Double) -> (Bool))?, handler: @escaping (AVURLAsset?, Error?) -> Void ) /// Requests video player item func requestAVPlayerItem( progressHandler: ((Double) -> (Bool))?, handler: @escaping (AVPlayerItem?, Error?) -> Void ) } ``` ### Step 2 Implement custom `UIViewController` inherited from `AlbumsViewController`: ```swift @objc open class AlbumsViewController: UIViewController { open weak var delegate: AlbumsViewControllerDelegate? open var configuration: AlbumsConfiguration? open var selectedAlbum: AlbumModel? } ``` - `delegate` - notifies `BanubaVideoEditorSDK` about actions that happen in Albums. These are the possible actions: ```swift @objc public protocol AlbumsViewControllerDelegate: AnyObject { /// Tells delegate object about selection the new album func albumsViewController(_ controller: AlbumsViewController, didSelect album: AlbumModel) // Tells delegate object about close action func albumsViewControllerDidClose(_ controller: AlbumsViewController) } ``` - `configuration` - a simple configuration with the `TextButtonConfiguration` and `BackButtonConfiguration` configurations; - `selectedAlbum` - an entity which contains information about the currently selected album: ```swift @objc public protocol AlbumModel { /// Album name var name: String? { get set } /// Album preview var preview: UIImage? { get set } /// Assosiated asset collection with album var assetCollection: PHAssetCollection { get } } ``` ### Step 3 Provide your custom gallery to `BanubaVideoEditorSDK`. Please, follow these steps: - create your own viewControllerFactory that conforms to `GalleryViewControllerFactory`: ```swift @objc public protocol GalleryViewControllerFactory: NSObjectProtocol { /// Creates GalleryViewController func makeGalleryViewController( withConfiguration configuration: GalleryConfiguration, selectionBehaviour: GallerySelectionBehaviour ) -> GalleryViewController } class MyGalleryViewControllerFactory: NSObject, GalleryViewControllerFactory { func makeGalleryViewController( withConfiguration configuration: BanubaUtilities.GalleryConfiguration, albumsConfiguration: BanubaUtilities.AlbumsConfiguration, selectionBehaviour: BanubaUtilities.GallerySelectionBehaviour ) -> BanubaUtilities.GalleryViewController { let controller = UIStoryboard( name: String(describing: UIViewController.self), bundle: Bundle(for: UIViewController.self) ).instantiateInitialViewController() as! UIViewController return controller } } ``` - paste your factory to the `BanubaVideoEditor` init: ```swift /// Example video editor view controller factory class ViewControllerFactory: ExternalViewControllerFactory { var musicEditorFactory: MusicEditorExternalViewControllerFactory? var countdownTimerViewFactory: CountdownTimerViewFactory? var exposureViewFactory: AnimatableViewFactory? //MARK: - ExternalViewControllerFactory protocols variale var galleryViewControllerFactory: GalleryViewControllerFactory? } ... let viewControllerFactory = ViewControllerFactory() // Paste your custom factory to externalViewControllerFactory viewControllerFactory.galleryViewControllerFactory = MyGalleryViewControllersFactory() videoEditorSDK = BanubaVideoEditor( token: token, configuration: config, externalViewControllerFactory: viewControllerFactory ) ``` --- ## Green Screen on iOS Video Editor SDK brings you real-time background subtraction technology for you to empower your users with the best quality virtual background service. Users can automatically remove, change or augment backgrounds. :::important The feature requires Face AR product with [Background Subtraction](https://www.banuba.com/technology/background-subtraction) feature. Please contact Banuba representatives to know more about using this feature. :::   ```Green Screen``` feature doesn't require physical green screens, the neural networks do all the work. --- ## Open Photo Editor SDK from Camera screen on iOS This guide demonstrates how to open [Photo Editor SDK](https://www.banuba.com/photo-editor-sdk) just after taking a photo on Video Editor Camera screen. All recorded video or taken images on Camera screen can be handled using ```videoEditor``` of protocol ```BanubaVideoEditorDelegate```. Provide custom implementation of ```videoEditor``` method to override flow. ``` diff class ViewController: UIViewController, BanubaVideoEditorDelegate, BanubaPhotoEditorDelegate { ... // highlight-add-next-line func videoEditor(_ videoEditor: BanubaVideoEditor, shouldProcessMediaUrls urls: [URL]) -> Bool { // Filter media resources to find the target image for Photo Editor SDK guard let jpegURL = urls.first(where: { $0.pathExtension.lowercased() == "jpeg" }), let imageData = try? Data(contentsOf: jpegURL), !imageData.isEmpty, let resultImage = UIImage(data: imageData) else { return true } // Close Video Editor SDK videoEditor.dismissVideoEditor(animated: true) { DispatchQueue.main.async { [weak self] in guard let self else { return } // Calling clearSessionData() also removes any files stored in urls array videoEditorModule?.videoEditorSDK?.clearSessionData() // Use this launch config to open Photo Editor SDK let launchConfig = PhotoEditorLaunchConfig( hostController: self, entryPoint: .editorWithImage(resultImage) ) } } return false } } ``` --- ## Share video screen on iOS Share video screen allows users to easily share an exported video using popular social media services and OS specific components. :::info This is an optional screen that you can add to your video editing flow. ::: It can be configured by `SharingScreenConfiguration` which is provided to the `presentSharingViewController` function that shows the screen. `SharingScreenConfiguration` has two key properties: * `sharingModels` - describes what kind of sharing services are available on the sharing screen; * `facebookId` - a required option for Facebook/Instagram reels and stories: ```swift private func showSharingScreen(videoUrl: URL, exportCoverImages: ExportCoverImages?) { let config = SharingScreenConfiguration( sharingModels: [ SharingServiceModel( sharingType: .facebookReels, sharingTitle: "Facebook\nReels", sharingImage: UIImage(named: "FbReels") ?? UIImage() ), SharingServiceModel( sharingType: .facebookStories, sharingTitle: "Facebook\nStories", sharingImage: UIImage(named: "FbStories") ?? UIImage() ), SharingServiceModel( sharingType: .instagramStories, sharingTitle: "Instagram\nStories", sharingImage: UIImage(named: "InstStories") ?? UIImage() ), SharingServiceModel( sharingType: .other, sharingTitle: "Other", sharingImage: UIImage(named: "Share") ?? UIImage() ) ], videoImageViewCornerRadius: 15.0, sharingVideoTextConfiguration: TextConfiguration( font: UIFont.boldSystemFont(ofSize: 22.0), color: .white, text: "Share video" ), backgroundConfiguration: BackgroundConfiguration( cornerRadius: 15.0, color: #colorLiteral(red: 0.1215686275, green: 0.1294117647, blue: 0.1411764706, alpha: 1) ), sharingCellConfiguration: SharingCellConfiguration( titleTextConfiguration: TextConfiguration( font: UIFont.systemFont(ofSize: 10.0), color: #colorLiteral(red: 0.4756349325, green: 0.4756467342, blue: 0.4756404161, alpha: 1) ) ), closeButtonConfiguration: RoundedButtonConfiguration( textConfiguration: TextConfiguration( font: UIFont.systemFont(ofSize: 12.0), color: .white, text: "CLOSE" ), cornerRadius: 20.0, backgroundColor: .clear, borderWidth: 1.0, borderColor: #colorLiteral(red: 0.4756349325, green: 0.4756467342, blue: 0.4756404161, alpha: 1) ), facebookId: "YOUR FACEBOOK APP ID" ) BanubaVideoEditor.presentSharingViewController( from: self, configuration: config, mainVideoUrl: videoUrl, videoUrls: [videoUrl], previewImage: exportCoverImages?.coverImage ?? UIImage(), animated: true, completion: nil ) } ``` --- ## Stickers on iOS Guide to using stickers in Video Editor SDK on Android. ## Giphy Video Editor SDK has built in integration with [Giphy service](https://developers.giphy.com/docs/api/) for loading stickers. ```GIPHY``` doesn't charge for their content. The one thing they do require is attribution. Also, there is no commercial aspect to the current version of the product (no advertisements, etc.). Any sticker effect is a GIF file. To use stickers in your project you need to request personal [Giphy API key](https://support.giphy.com/hc/en-us/articles/360020283431-Request-A-GIPHY-API-Key). Set your personal Giphy Api Key into the `giphyAPIKey` parameter of the `GifPickerConfiguration` entity in the [VideoEditorModule](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/VideoEditorModule.swift#L83): ```swift var config = VideoEditorConfig() config.gifPickerConfiguration.giphyAPIKey = "YOUR GIPHY KEY" ``` Stickers will appear in the container on editor screen once ```giphyAPIKey``` is set. The placeholder of the search bar is specified by the `com.banuba.searchGif.placeholder` key in the `Localizable.strings` file. --- ## Video recording integration guide on iOS Guide to modifying video recording feature in Video Editor SDK. ## Quality details The subsequent table describes video quality details used for video recording in various resolutions with h264 codec. If h265 (HEVC) codec is used for recording a video, the values listed below will be reduced by approximately 34%: | Recording speed | 360p(360 x 640) | 480p(480 x 854) | 540p(540 x 960) | HD(720 x 1280) | FHD(1080 x 1920) | QHD(2560 x 1440) | 4K(3860 x 2160) | | -------------------------- | --------------- | --------------- | --------------- | --------------- | ---------------- | ---------------- | --------------- | | 0.5x, 1x (Default), 2x, 3x | 1.2 Mbits | 2 Mbits | 2.4 Mbits | 3.6 Mbits | 5.8 Mbits | 16 Mbits | 36 Mbits | ## Implement configurations `VideoEditorConfig` is the core class used for customizing all features in the Video Editor SDK. The class includes many internal config classes that are very useful if you want to create your custom experience. `RecorderConfiguration` is the main configuration class in `VideoEditorConfig` and is used for the video recording functionality: | Property | Values | Description | | ------------- |:-----------------------------------:| :------------- | | videoResolution | VideoResolutionConfiguration | defines the resolution configuration for a video recording | loopAudioWhileRecording | Bool; Default `true` | defines if the audio used in the video recording should be looped | isDynamicMusicTitle | Bool; Default `false` | defines if the music title on the screen changes when a new track is applied | isDefaultFrontCamera | Bool; Default `false` | set `true` if you want to open camera in the front mode | useHEVCCodecIfPossible | Bool; Default `true` | enables H265 codec for recording if it is available on the device | isPhotoSequenceAnimationEnabled | Bool; Default `false` | should use animation for photo sequences | isAudioRateEqualsVideoSpeed | Bool; Default `false` | the video speed selected by the user is applied to audio | isGalleryButtonHidden | Bool; Default `false` | defines if the gallery button located in the bottom-right should be hidden. `true` will hide the button | supportMultiRecords | Bool; Default `true` | defines if the user can record multiple video files | takeAudioDurationAsMaximum | Bool; Default `false` | limits the maximum length of a video recording to match the duration of the audio used in the recording The next very handy config class is `VideoEditorDurationConfig` that is responsible for customizing video recording durations: :::warning All values are in seconds. ::: | Property | Values | Description | | ------------- |:-----------------------------------------------------------:| :------------- | | maximumVideoDuration | TimeInterval > 0; Default `120.0` | the maximum allowed video duration | videoDurations | [TimeInterval] not empty; Default `[60.0, 30.0, 15.0]` | the array of durations allowed for the video recording. The user sees a certain button and can change the duration by tapping. For example, `60.0` means that the user can record multiple video sources with the total duration no more than `60.0` seconds. | minimumDurationFromCamera | TimeInterval > 0; Default `3.0` | the minimum allowed video duration required to proceed and open the next screen | minimumDurationFromGallery | TimeInterval > 0; Default `0.3` | the minimum allowed video duration displayed on the gallery screen | minimumVideoDuration | TimeInterval > 0; Default `1.0` | the minimum allowed video source duration that can be recorded on the camera screen | minimumTrimmedPartDuration | TimeInterval > 0; Default `0.3` | the minimum allowed video source duration to trim | slideshowDuration | TimeInterval > 0; Default `0.3` | the slideshow video duration produced by an image In this example, the maximum video recording duration is set to 30 seconds: ```swift var config = VideoEditorConfig() config.videoDurationConfiguration.maximumVideoDuration = 30.0 ``` And `FeatureConfiguration` that helps to customize the use of some specific features on the camera screen where the video recording happens: | Property | Values | Description | | ------------- |:-------------------------:| :------------- | | isDoubleTapForToggleCameraEnabled | Bool; Default `false` | enables switching between the front and the back camera facing by double tapping on the camera screen | isMuteCameraAudioEnabled | Bool; Default `false` | indicates if the "mute microphone" button is visible on the camera screen | isSpeedBarEnabled | Bool; Default `true` | enables the speed selection bar. If the bar is disabled, the speed recording will be interactively switched by tapping | openAutomaticallyPIPSettingsDropdown | Bool; Default `false` | if this property is enabled, the PiP settings drop down view will be presented after opening the camera screen ## Configure the microphone state The `RecorderConfiguration` class includes the `muteMicrophoneForPIP` property you can use to mute the sound in the PIP mode. The default value is `true`: ```swift var config = VideoEditorConfig() config.recorderConfiguration.muteMicrophoneForPIP = false ``` ## Configure recording modes The recording includes 3 modes for recording content implemented in `captureButtonModes` in the `RecorderConfiguration` class: - `Photo`, - `Video`, - `Photo` and `Video` - **default**. In this example, the recording mode is set to `Video` only: ```swift var config = VideoEditorConfig() config.recorderConfiguration.captureButtonModes = [.video] ``` ## Configure the record button appearance The record button is the main UI control on the camera screen which you can fully customize along with the animation that is played by tapping. Implement the `RecordButtonProvider`, `RecordButton`, `RecordButtonDelegate` protocols to create your custom recording button experience: ```swift public protocol RecordButtonProvider { func getButton() -> RecordButton } public protocol RecordButton: UIView { var delegate: RecordButtonDelegate? { get set } var configuration: RecordButtonConfiguration? { get set } func changeViewToIdleState() func changeViewToRecordingState() } public protocol RecordButtonDelegate: AnyObject { var captureButtonMode: CaptureButtonViewMode { get } func recordButtonDidTakePhoto(_ recordButton: RecordButton) func recordButtonDidCancelTakePhoto(_ recordButton: RecordButton) func recordButtonDidStartVideoRecording(_ recordButton: RecordButton) func recordButtonDidStopVideoRecording(_ recordButton: RecordButton) func recordButtonDidZoomingVideoRecording(_ recordButton: RecordButton, recognizer: UILongPressGestureRecognizer) } ``` Set the new implementation of `RecordButtonProvider` to `RecorderConfiguration.recordButtonProvider`: ```swift var config = VideoEditorConfig() config.recorderConfiguration.recordButtonProvider = ... ``` ## Camera Layout Camera Layout is a set of camera recording layouts that combine the camera feed with additional media in a single video: background replacement, `weatherman` overlays and the classic `Picture in Picture` split screens. It replaces the standalone `PIP` screen used before `1.54.2`. See [Camera Layouts](guide_camera_layouts.md) for the full guide, the list of supported layouts and the migration steps from `PIP`. --- ## Weatherman on iOS Weatherman mode is an improvement on top of Banuba's cutting-edge background replacement. It allows users to drag and drop themselves on any place on the screen to emulate the look of a TV presenter the feature is named after. Weatherman is useful for reactions, learning content, presentations, explainers and other similar videos thanks to the professional feel it creates. :::important The Weatherman feature is disabled by default. Please contact Banuba representatives to know more about using this feature. :::     --- ## Integration Video Editor on iOS ## Installation ### CocoaPods :::warning CocoaPods version 1.12.1 or newer is required. Check your version with pod --version and upgrade if needed. ::: To integrate the Video Editor SDK via CocoaPods: The List of the required Video Editor dependencies is present in the sample project's [Podfile](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Podfile). Complete the following steps to get the Video Editor SDK dependencies using CocoaPods: 1. Install CocoaPods (if not already installed) using Homebrew: ```sh brew install cocoapods ``` 2. Initialize CocoaPods in your project folder: ```sh pod init ``` 3. Add sources and pods to your Podfile: ```ruby source 'https://cdn.cocoapods.org/' source 'https://github.com/Banuba/specs.git' source 'https://github.com/sdk-banuba/banuba-sdk-podspecs.git' banuba_sdk_version = '1.52.1' pod 'BanubaVideoEditorSDK', banuba_sdk_version pod 'BanubaSDKSimple', banuba_sdk_version pod 'BanubaSDK', banuba_sdk_version pod 'BanubaARCloudSDK', banuba_sdk_version # optional pod 'BanubaAudioBrowserSDK', banuba_sdk_version # optional ``` 4. Install the pods: ```sh pod install --repo-update ``` 5. Open the generated ```.xcworkspace``` in Xcode and run the project. ### Swift Package Manager Learn the [SPM Getting Started Guide](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app) if you are new to SPM. SPM integration is available in the [spm branch](https://github.com/Banuba/ve-sdk-ios-integration-sample/tree/spm). :::note The following guide is compatible with the VE SDK v1.31.3 and newer. If you are looking for a way to install v1.31.2 or older with SPM, please, visit the [legacy docs](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/mdDocs/quickstart.md#spm) ::: Complete the following steps to get the Video Editor SDK dependencies using SPM: 1. open `App project` and navigate to the `Package Dependencies` tab; 2. for every package that needs to be installed click the `plus` button and type its repo url; 3. choose `Exact Version` and type the newest SDK version. Check out the [Mandatory modules](./mandatory-modules.md) guide to learn more about the modules included in the Video Editor SDK and their compatibility with the Face AR SDK. ## Info.plist Updates Add the iOS permissions required by the SDK (camera, microphone, photo library, media library) to your [Info.plist](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/Info.plist): ```xml NSAppleMusicUsageDescription This app requires access to the media library NSCameraUsageDescription This app requires access to the camera. NSMicrophoneUsageDescription This app requires access to the microphone. NSPhotoLibraryUsageDescription This app requires access to the photo library. ``` ## Localization Add [English Localized Strings](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/en.lproj/Localizable.strings) file to the project. ## Video Editor Module Setup Custom behavior of Video Editor SDK in your app is implemented by using a number of configuration classes in the SDK. First, create new class [VideoEditorModule](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/VideoEditorModule.swift) for implementing configurations. ```swift class VideoEditorModule { } ``` Next, create ```VideoEditorConfig``` for implementing custom video editor configurations. ```swift class VideoEditorModule { func createConfiguration() -> VideoEditorConfig { var config = VideoEditorConfig() ... return config } } ``` ## Launch Create instance of ```BanubaVideoEditor``` by using the license token. ```swift let videoEditorSDK = BanubaVideoEditor( token: AppDelegate.licenseToken, configuration: config, externalViewControllerFactory: viewControllerFactory ) ``` ```videoEditorSDK``` is ```nil``` when the license token is incorrect i.e. empty, truncated. If ```videoEditorSDK``` is not ```nil``` you can proceed and start video editor. Check your license state before starting video editor: ```swift videoEditorSDK?.getLicenseState(completion: { [weak self] isValid in if isValid { print("✅ License is active, all good") } else { print("❌ License is either revoked or expired") } ... completion(isValid) }) ``` :::warning Video content unavailable screen will appear if you start Video Editor SDK with revoked or expired license. ::: The [implementation](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/ViewController.swift#L45) below starts Video Editor from camera screen. ```swift let cameraLaunchConfig = VideoEditorLaunchConfig( entryPoint: .camera, hostController: self, musicTrack: nil, // Paste a music track as a track preset at the camera screen to record video with music animated: true ) videoEditorModule.presentVideoEditor(with: cameraLaunchConfig) ``` ## Implement export The Video Editor SDK can export multiple files at once. To set up export: 1. Make an ExportConfiguration object. Add one or more ExportVideoConfiguration objects to it. Each one stands for a video or audio file. 2. Call BanubaVideoEditor.export() and pass your ExportConfiguration to start. Check the [export implementation](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/ViewController.swift#L250) in the sample. Read the [Export integration guide](https://docs.banuba.com/ve-pe-sdk/docs/ios/guide_export) for more details. --- ## Launching Photo Editor on iOS Guide to launching Photo Editor SDK. ## Launch Create an instance of `BanubaPhotoEditor` using the license token: ```swift var configuration = PhotoEditorConfig() let photoEditorSDK = BanubaPhotoEditor( token: token, configuration: configuration ) photoEditorSDK?.delegate = delegate photoEditorSDK?.presentPhotoEditor( withLaunchConfiguration: launchConfig, completion: nil ) ``` `photoEditorSDK` is `nil` when the license token is incorrect i.e. empty, truncated. If `photoEditorSDK` is not `nil`, you can proceed and start the Video Editor. Next, we strongly recommend checking your license state before starting the Photo Editor: ```swift photoEditorSDK?.getLicenseState(completion: { [weak self] isValid in if isValid { print("✅ License is active, all good") } else { print("❌ License is either revoked or expired") } ... completion(isValid) }) ``` :::danger The "Photo editing is unavailable" screen will appear if you start the Photo Editor SDK with a revoked or expired license. ::: :::warning If you have also integrated the Video Editor SDK into your app, make sure to deallocate any instances of `BanubaVideoEditor` that remain in memory before presenting the Photo Editor in order to prevent crashes: ::: ```swift videoEditorSDK = nil ... photoEditorSDK?.presentPhotoEditor( withLaunchConfiguration: launchConfig, completion: nil ) ``` ## Photo Editor Lifecycle Events To receive the notifications when a user has either closed the editor or finished editing and saved the edited photo, create a class that conforms to the `BanubaPhotoEditorDelegate` protocol and assign its reference to the `BanubaPhotoEditor.delegate` property: ```swift photoEditorSDK?.delegate = delegate ``` During handling of both notifications you must dismiss the Photo Editor: ```swift /// User closed photo editor without editing image func photoEditorDidCancel( _ photoEditor: BanubaPhotoEditorSDK.BanubaPhotoEditor ) { photoEditor.dismissPhotoEditor(animated: true, completion: nil) } /// User closed photo editor after saving image func photoEditorDidFinishWithImage( _ photoEditor: BanubaPhotoEditorSDK.BanubaPhotoEditor, image: UIImage ) { photoEditor.dismissPhotoEditor(animated: true, completion: nil) // Do something with received image } ``` --- ## SPM Mandatory modules The following modules must be installed in all cases: | Package name | GitHub link | |----------|-------------| | BanubaVideoEditorSDK-iOS | https://github.com/Banuba/BanubaVideoEditorSDK-iOS | If you are **not** using the Face AR SDK together with the VE, you must add one additional module: | Package name | GitHub link | |----------|-------------| | BanubaSDKSimple-IOS | https://github.com/Banuba/BanubaSDKSimple-IOS | ## Face AR interoperation modules If your license includes the Face AR SDK, please, add the additional modules listed below: | Package name | GitHub link | |----------|-------------| | BanubaSDK-iOS | https://github.com/Banuba/BanubaSDK-iOS | The Face AR packages (`BNB***`) hosted by the `sdk-banuba` account follow their own versioning. The following table specifies the mapping between the compatible VE and Face AR versions. Please, make sure that you specify the correct Face AR version, otherwise run-time incompatibilities may arise leading to crashes: | Video Editor SDK versions | Compatible FaceAR SDK version | |----------------------------------------|-------------------------------| | 1.48.0 | 1.17.5 | | 1.47.0, 1.47.1, 1.47.2 | 1.17.4 | | 1.44.0, 1.45.0, 1.45.1 , 1.46.0 | 1.17.3 | | 1.43.0 | 1.17.1 | | 1.42.0, 1.42.1 | 1.17.0 | | 1.39.0, 1.40.0, 1.41.0 | 1.16.1 | | 1.38.1 | 1.15.2 | | 1.38.0, 1.37.0, 1.36.6 | 1.14.2 | | 1.36.2 | 1.14.1 | | 1.36.0 | 1.14.0 | | 1.35.1 | 1.12.0 | | 1.35.0 | 1.11.1 | | 1.34.1, 1.34.0, 1.33.3, 1.33.2, 1.33.1 | 1.10.1 | | 1.33.0 | 1.9.3 | | 1.32.2, 1.32.1, 1.32.0 | 1.9.1 | If your license includes [AR Cloud](guide_far_arcloud.md), please, also add the following package: | Package name | GitHub link | |----------|-------------| | BanubaARCloudSDK-IOS | https://github.com/Banuba/BanubaARCloudSDK-IOS | ## Optional modules You may skip the module below only if your app provides custom implementations of [Audio Browser](guide_audio_content.md). Otherwise make sure to add it to your project: | Package name | GitHub link | |----------|-------------| | BanubaAudioBrowserSDK-iOS | https://github.com/Banuba/BanubaAudioBrowserSDK-iOS | --- ## Installation with CocoaPods Learn the [CocoaPods Getting Started Guide](https://guides.cocoapods.org/using/getting-started.html) if you are new to CocoaPods. :::info It is advised to use the latest version of CocoaPods. Please, check your version with ```pod --version``` and upgrade it if necessary. ::: Complete the following steps to get the Photo Editor SDK dependencies using CocoaPods: 1. install CocoaPods using Homebrew: ```sh brew install cocoapods ``` 2. create a new Podfile in your project folder or edit the existing one: ```sh pod init ``` 3. add the necessary pods and our podspecs sources to the Podfile. The list of the required Photo Editor dependencies can be found in the [Podfile](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Podfile) example: ```ruby source 'https://cdn.cocoapods.org/' source 'https://github.com/Banuba/specs.git' source 'https://github.com/sdk-banuba/banuba-sdk-podspecs.git' pod 'BanubaPhotoEditorSDK', '1.3.6' ``` 4. install the Video Editor SDK pods: ```sh pod install --repo-update ``` 4. open the ```***.xcworkspace``` workspace in Xcode and run the project. --- ## Configure Photo Editor on iOS Guide to modifying Photo Editor SDK. ## Initial screen (entry point) selection By default the built-in gallery will be shown first after the presentation of the Photo Editor. In some cases the hosting app may already provide the photo selection functionality using its own custom gallery and it is necessary to directly open the photo editing screen with a preselected photo. To support such use cases there is the `entryPoint` property in `PhotoEditorLaunchConfig`. By using the `editorWithImage` or `editorWithURL` options you can specify the edited image by directly providing either the `UIImage` instance or the *local* `URL` to the on-disk binary image representation. In the following example the image stored in the app's bundle will be opened in the Photo Editor SDK: ```swift let url = Bundle.main.url(forResource: "image", withExtension: "jpg")! let launchConfig = PhotoEditorLaunchConfig( hostController: ..., entryPoint: .editorWithURL(url) ) photoEditorSDK.presentPhotoEditor( withLaunchConfiguration: launchConfig, completion: nil ) ``` Should there be any problem with decoding the image at the provided url, an error message will be logged into the console by the SDK. ## Configuration of the sharing screen After finishing editing an image, a user is navigated to the Sharing screen. If Facebook or Instagram is installed on the user's phone, it will be possible to present an option to share the image as a Facebook or Instagram Story. To enable such a functionality you need to specify the Facebook app id: ```swift var configuration = PhotoEditorConfig() configuration.previewScreenMode = .enabled( previewScreenConfiguration: .init( shareButtonsMode: .enabled( shareButtonsConfiguration: .init(facebookId: "1234567890") ) ) ) let photoEditorSDK = BanubaPhotoEditor( token: "***", configuration: configuration ) ``` Read more about sharing to Instagram and Facebook stories at https://developers.facebook.com/docs/instagram/sharing-to-stories/. The sharing screen can be disabled entirely. In such case a user will be redirected back to your hosting app after tapping the "Save" button at image editing screen: ```swift var configuration = PhotoEditorConfig() configuration.previewScreenMode = .disabled ``` Alternatively, you can also hide the social networks sharing buttons while keeping the sharing screen: ```swift var configuration = PhotoEditorConfig() configuration.previewScreenMode = .enabled( previewScreenConfiguration: .init(shareButtonsMode: .disabled) ) ``` ## Disable publishing image to Gallery ```swift var configuration = PhotoEditorConfig() configuration.editorScreenConfiguration = .init(saveResultToPhotoLibrary: false) ``` ## Add localization strings The Photo Editor SDK displays a number of strings that can be freely changed in the Localizable.strings file of your app. Please, make sure that you've included all the strings with the `photoEditor` key prefix in your app's Localizable.strings file from the [Localized Strings](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/main/Example/Example/en.lproj/Localizable.strings) file provided with the sample project to prevent placeholders from showing up in the photo editor's UI. If you are still seeing placeholders, make sure that the App Language in the Xcode Scheme Options is set to English as this is the only language supported by this demo app. --- ## Banuba Photo Editor SDK Requirements on iOS Guide contains general requirements for using Photo Editor SDK on iOS. ## License Token Before you commit to a license, you are free to test all the features of the SDK for free. The trial period lasts 14 days. Send us a message to start the [Photo Editor SDK trial](https://www.banuba.com/photo-editor-sdk#form). We will get back to you with the trial token. Feel free to contact us if you have any questions regarding the [Photo Editor SDK](https://www.banuba.com/support). ## Project settings This is what you need to run the AR Photo Editor SDK: - Swift 5.10 or newer, - Xcode 26.0 or newer, - iOS 15.0 or newer. ## SDK size | Photo Editor | Total size | |:------------:|:----------:| |:white_check_mark:| 121 MB | --- ## Installation with Swift Package Manager on iOS Learn the [SPM Getting Started Guide](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app) if you are new to SPM. The integration of the PE SDK via SPM is demonstrated in the [spm branch](https://github.com/Banuba/ve-sdk-ios-integration-sample/tree/spm) of our native sample. Complete the following steps to get the Photo Editor SDK dependencies using SPM: 1. open `App project` and navigate to the `Package Dependencies` tab; 2. for every package that needs to be installed click the `plus` button and type its repo url; 3. choose `Exact Version` and type the newest SDK version. The following module must be installed: | Package name | GitHub link | |----------|-------------| | BanubaPhotoEditorSDK-iOS | https://github.com/Banuba/BanubaPhotoEditorSDK-iOS | --- ## Requirements(Ios) # Banuba Video Editor SDK on iOS ## License Token Before you commit to a license, you are free to test all the features of the SDK for free. The trial period lasts 14 days. Send us a message to start the [Video Editor SDK trial](https://www.banuba.com/video-editor-sdk#form). We will get back to you with the trial token. Feel free to contact us if you have any questions regarding [Video Editor SDK](https://www.banuba.com/support). ## Project settings This is what you need to run the AI Video Editor SDK: - Swift 5.9 or newer, - Xcode 26.0 or newer, - iOS 15.0 or newer. - :white_check_mark: arm64, :white_check_mark: arm64e, :exclamation: x86-64 limited support ## Supported media formats | Audio | Video | Images | | ---------- | --------- | ----------- | |.mp3, .aac, .wav, .m4a, .flac, .aiff | .mp4, .mov, .m4v | .bmp, .gif, .heic, .jpeg, .jpg, .png, .tiff ## SDK size Banuba Video Editor SDK with all the core editing features only adds 14 Mb of space to your app’s download size. This parameter can change based on the number of features you want. |SDK| Total size | |:------------|:-----------:| |Banuba Video Editor SDK (core editor)| 14 Mb | |Banuba Video Editor SDK (full bundle)| 45 Mb | |Video Editor with Photo Editor | 80 Mb | |Video Editor with face augmented reality features | 45 - 140 Mb | --- ## FAQ on iOS These are the answers to the most common questions asked about our SDK. ## How do I start the Video Editor with a preselected audio track? To do so, add the MediaTrack instance as a parameter to `VideoEditorLaunchConfig` which is used for starting the Video Editor method: ```swift let cameraLaunchConfig = VideoEditorLaunchConfig( entryPoint: .camera, hostController: self, musicTrack: MediaTrack(...), animated: true ) videoEditorSDK?.presentVideoEditor( withLaunchConfiguration: cameraLaunchConfig, completion: nil ) ``` ## What are the available entry points of the Video Editor? The Video Editor supports multiple launch entry points that are declared in `PresentEventOptions.EntryPoint` to meet all your requirements: ``` swift public enum EntryPoint: String, Codable { case camera case pip case trimmer case editor case drafts case gallery } ``` To open the Video Editor at the desired screen, use `VideoEditorLaunchConfig` that should be passed to the `presentVideoEditor` method of the `BanubaVideoEditor` class: ``` swift public func presentVideoEditor( withLaunchConfiguration configuration: VideoEditorLaunchConfig, completion: (() -> Void)? ) {} ``` 1. Launch from the Camera screen where the user can record a video or take a picture: ``` swift let launchConfig = VideoEditorLaunchConfig( entryPoint: .camera, hostController: UIViewController, musicTrack: MediaTrack, animated: Bool ) videoEditorSDK.presentVideoEditor( withLaunchConfiguration: launchConfig, completion: nil ) ``` 2. Launch from the Camera screen in the Picture-in-Picture (PIP) mode: :::important The Video Editor will not open in the PIP mode if your license token does not support the PIP feature. ::: ``` swift let launchConfig = VideoEditorLaunchConfig( entryPoint: .pip, hostController: UIViewController, pipVideoItem: URL, animated: Bool ) videoEditorSDK.presentVideoEditor( withLaunchConfiguration: launchConfig, completion: nil ) ``` 3. Launch from the Trimmer screen where the user can trim a video, add transitions and move to the editing screen for adding effects: ``` swift let launchConfig = VideoEditorLaunchConfig( entryPoint: .trimmer, hostController: UIViewController, videoItems: [URL], musicTrack: MediaTrack, animated: Bool ) videoEditorSDK.presentVideoEditor( withLaunchConfiguration: launchConfig, completion: nil ) ``` 4. Launch from the Editor screen where the user can add effects to a video: ``` swift let launchConfig = VideoEditorLaunchConfig( entryPoint: .editor, hostController: UIViewController, videoItems: [URL], musicTrack: MediaTrack, animated: Bool ) videoEditorSDK.presentVideoEditor( withLaunchConfiguration: launchConfig, completion: nil ) ``` 5. Launch from the Drafts screen where the user can pick any non-completed draft and proceed with making a video: ``` swift let launchConfig = VideoEditorLaunchConfig( entryPoint: .drafts, hostController: UIViewController, animated: Bool ) videoEditorSDK.presentVideoEditor( withLaunchConfiguration: launchConfig, completion: nil ) ``` 6. Launch from the Gallery screen where the user can select videos or photos and proceed to the Editor screen: ``` swift let launchConfig = VideoEditorLaunchConfig( entryPoint: .gallery, hostController: UIViewController, animated: Bool ) videoEditorSDK.presentVideoEditor( withLaunchConfiguration: launchConfig, completion: nil ) ``` ## How do I use the Video Editor several times from different entry points? Before you want to use VideoEditor again, you need to deinitialize your current editor instance in your [entry point class scope](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/d9733e78a6a752dd8fad849f6aa6d5553eb07f56/Example/Example/ViewController.swift#L675). You need to set 'yourVideoEditorSdkInstance' = nil after following the funcs called [done](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/d9733e78a6a752dd8fad849f6aa6d5553eb07f56/Example/Example/ViewController.swift#L660) and [cancel](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/d9733e78a6a752dd8fad849f6aa6d5553eb07f56/Example/Example/ViewController.swift#L678): ```swift // Video Editor Delegate implementation example extension ViewController: BanubaVideoEditorDelegate { func videoEditorDone(_ videoEditor: BanubaVideoEditor) { // User finished editing sessoin, need to dismiss video editor and export video videoEditorSDK?.dismissVideoEditor( animated: true ) { [weak self] in self?.exportVideo(...) { ... in self?.'yourVideoEditorSdkInstance' = nil } } } func videoEditorDidCancel( _ videoEditor: BanubaVideoEditor ) { // User canceled editing sessoin, need to dismiss video editor videoEditorSDK?.dismissVideoEditor( animated: true, completion: { self?.'yourVideoEditorSdkInstance' = nil } ) } } ``` Use the following approach if you want to [create the BanubaVideoEditor instance](https://github.com/Banuba/ve-sdk-ios-integration-sample/blob/d9733e78a6a752dd8fad849f6aa6d5553eb07f56/Example/Example/ViewController.swift#L42) again. For example, as your tap button action: ```swift @IBAction func videoEditorButtonTapped(_ sender: UIButton) { if 'yourVideoEditorSdkInstance' == nil { 'yourVideoEditorSdkInstance' = BanubaVideoEditor(...) } } ``` ## How do I add a color filter (LUT)? Color Filters (LUTs) are special graphic files that are placed in the / [luts directory](https://github.com/Banuba/ve-sdk-ios-integration-sample/tree/main/Example/Example/luts) inside the main project folder. To add your own icon to be used in order to represent that specific effect on the list, you must place it in the / [assets folder](https://github.com/Banuba/ve-sdk-ios-integration-sample/tree/main/Example/Example/Assets.xcassets/ColorEffectsPreview). The icon resource name must match the image file name in the / luts directory and end with `_preview`. The display name for the resource is set in the [localization files](https://github.com/Banuba/ve-sdk-ios-integration-sample/tree/main/Example/Example/en.lproj/Localizable.strings#L275). The key for the translation string must start with `com.banuba.filter.name.{lut file name}` and end with the name of the lut file. ## I want to enable the slideshow animation. To be able to turn on the slideshow animation, use the following property of the `RecorderConfiguration` and `CombinedGalleryConfiguration` entities: ```swift let config = VideoEditorConfig() config.combinedGalleryConfiguration.isPhotoSequenceAnimationEnabled = true config.recorderConfiguration.isPhotoSequenceAnimationEnabled = true ``` ## I want to change the cursor color. All you need is just to set your color into the `cursorColor` parameter in the `MainOverlayViewControllerConfig` entity: ```swift let config = VideoEditorConfig() config.overlayEditorConfiguration.mainOverlayViewControllerConfig.cursorColor = .white ``` ## How can I get the track name of the audio used in my video after the export? ```swift /// Video Editor main entity and entry point. /// Can present and hide root view controller. /// Has default export method. public class BanubaVideoEditor { /// Simple metadata of music composition settings public var musicMetadata: MusicEditorMetadata? { get } ... } ``` `MusicEditorMetadata` contains the array of `MusicEditorTrack` which contains the following fields: ```swift // MARK: - MusicEditorTrack public struct MusicEditorTrack: Codable { ///Track URL public var url: URL ///Track original URL public var originalURL: URL ///Track title public var title: String ///Track id public var id: Int32 /// Track volume public var volume: Float ... } ``` or if you want to know what track was played on the camera screen, you can use: ```swift /// Video Editor main entity and entry point. /// Can present and hide root view controller. /// Has default export method. public class BanubaVideoEditor { /// Music track which will be played on camera recording public var musicTrack: MediaTrack? { get } ... } ``` ## I want to change the font. You can change the font for the whole Video Editor by calling in `VideoEditorConfig` this method: ```swift func applyFont(_ font: UIFont) ``` or change the font for each screen separately by calling the appropriate methods: ```swift func updateFullScreenActivityFonts(_ font: UIFont) func updateRecorderFonts(_ font: UIFont) func updateAlbumsFonts(_ font: UIFont) func updateEditorFonts(_ font: UIFont) func updateToastFonts(_ font: UIFont) func updateTextEditorFonts(_ font: UIFont) func updateSlideShowFonts(_ font: UIFont) func updateTrimVideoFonts(_ font: UIFont) func updateTrimVideosFonts(_ font: UIFont) func updateFilterFonts(_ font: UIFont) func updateExtendedVideoCoverSelectionFonts(_ font: UIFont) func updateAlertFonts(_ font: UIFont) ``` Changing the font does not affect its size. The font size will be taken by default or specified by you in the entity configuration. ## I want to use custom icons. Any icon in the mobile Video Editor SDK can be replaced. This is how: 1. load custom images to the Assets catalog; 2. locate the screen with the icon you want to change in the [VideoEditorConfig](https://github.com/Banuba/ve-sdk-ios-integration-sample/tree/main/Example/Example/VideoEditorModule.swift#L75) entity. More examples: [Camera Screen](guide_camera.md), [Editor Screen](guide_editor.md); 3. find the specific element and override it with the resource name or use UIImage if available. ## The “luts” file couldn’t be opened because there is no such file. This error occurs because your application bundle doesn't contain the required luts folder. You need to copy the [luts](https://github.com/Banuba/ve-sdk-ios-integration-sample/tree/main/Example/Example/luts) folder to your project. ## I want to add audio filters. The filters' availability depends on the token. However, in order for them to be available, you need to add an implementation of the `VoiceFilterProvider` entity. Here is an example on how to inherit `VoiceFilterProvider` to your own entity: ```swift import BanubaMusicEditorSDK import UIKit /// Example voice filter provider struct ExampleVoiceFilterProvider: VoiceFilterProvider { private let filters: [VoiceFilter] // MARK: - VoiceFilterProvider func provideFilters() -> [VoiceFilter] { return filters } init() { filters = [ VoiceFilter( type: .elf, title: NSLocalizedString("com.banuba.musicEditor.elf", comment: "Elf filter title"), image: UIImage(named:"elf") ), VoiceFilter( type: .baritone, title: NSLocalizedString("com.banuba.musicEditor.baritone", comment: "Baritone filter title"), image: UIImage(named:"baritone") ), VoiceFilter( type: .echo, title: NSLocalizedString("com.banuba.musicEditor.echo", comment: "Echo filter title"), image: UIImage(named:"echo") ), VoiceFilter( type: .giant, title: NSLocalizedString("com.banuba.musicEditor.giant", comment: "Giant filter title"), image: UIImage(named:"giant") ), VoiceFilter( type: .robot, title: NSLocalizedString("com.banuba.musicEditor.robot", comment: "Robot filter title"), image: UIImage(named:"robot") ), VoiceFilter( type: .squirrel, title: NSLocalizedString("com.banuba.musicEditor.squirrel", comment: "Squirrel filter title"), image: UIImage(named:"squirrel") ) ] } } ``` Then the instance of ExampleVoiceFilterProvider needs to be passed to the configuration: ```swift var config = VideoEditorConfig() config.musicEditorConfiguration.audioTrackLineEditControllerConfig.voiceFilterProvider = ExampleVoiceFilterProvider() ``` ## I want to change icons and name for effects. The name of the icon for the effect must match the identifier of the effect. Below there is a table with the name, ID and icon of the default effects: | Default image effect | Name | ID | | ---------- | --------- | ----------- | | | Acid whip | 102000 | | Cathode | 102001 | | DV Cam | 102002 | | Flash | 102003 | | Glitch | 102004 | | Glitch 2 | 102005 | | Heat Map | 102006 | | Lumiere | 102007 | | Mirror | 102008 | | Mirror 2 | 102009 | | Pixel Dynamic | 102010 | | Pixel Static | 102011 | | Polaroid | 102012 | | Rave | 102013 | | Soul | 102014 | | Stars | 102015 | | TV-Foam | 102016 | | Transition | 102017 | | Transition 2 | 102018 | | VHS | 102019 | | VHS 2 | 102020 | | Zoom | 102021 | | Zoom 2 | 102022 | | 0.5x | 104000 | | 2x | 104001 In order to change the name of the effect, you need to do it in the [localization file](https://github.com/Banuba/ve-sdk-ios-integration-sample/tree/main/Example/Example/en.lproj/Localizable.strings#L254). ## I want to get the exported video metadata. In order to find out which filter, effects, masks and music were applied to the video, you need to refer to the instance of the `BanubaVideoEditor` entity. The instance: ``` swift let videoEditorSDK = BanubaVideoEditor( ... ) // to get color filter let videoFilter = videoEditorSDK?.metadata?.colorOnVideoMetadata // to get effects let videoEffects = videoEditorSDK?.metadata?.effectsOnVideoMetadata // to get gifs let videoGif = videoEditorSDK?.metadata?.gifOnVideoMetadata // to get texts let videoText = videoEditorSDK?.metadata?.textOnVideoMetadata // to get music track from record screen let videoMusicTrack = videoEditorSDK?.musicTrack // to get music tracks from editor screen let videoTracks = videoEditorSDK?.musicMetadata?.tracks ``` ## I want to change the codec type from h264 to h265. All you need is to just set `useHEVCCodecIfPossible` to `true` in the `VideoEditorConfig, ExportVideoInfo or ExportVideoConfiguration` entities. The first one you need when you're creating `BanubaVideoEditor`, the two last ones - when you're preparing a video for export: ```swift let exportVideoInfo = ExportVideoInfo( resolution: ..., useHEVCCodecIfPossible: true ) let configuration = ExportVideoConfiguration( fileURL: ..., quality: ..., useHEVCCodecIfPossible: true, watermarkConfiguration: ... ) ``` ## How do I specify the video file saving directory? In `ExportVideoConfiguration` set the desired path in the fileURL parameter: ```swift let exportVideoConfigurations: [ExportVideoConfiguration] = [ ExportVideoConfiguration( fileURL: fileURL, quality: .auto, useHEVCCodecIfPossible: true, watermarkConfiguration: watermarkConfiguration ) ] ``` ## How do I change the language (how do I add new locale support)? There is no special language switching mechanism in the Video Editor SDK (VE SDK). Out of the box, the VE SDK includes support for two locales: English (default) and Russian. If you need to support any other locales, you can do it according to the standard iOS way. See how to [create locale directories and resource files](https://developer.apple.com/documentation/xcode/localization) for more details. After adding a new locale resource file into your application with the integrated VE SDK, you need to re-define the VE SDK strings keys with the new locale string values. To do that, you need to add all the needed string keys in the new locale `Localizable.strings` file. You can find the main VE SDK string keys you need in the [Localizable.strings](https://github.com/Banuba/ve-sdk-ios-integration-sample/tree/main/Example/Example/en.lproj/Localizable.strings) file. The newly added locale will be applied after the device language is changed by the system settings. ## How can I change the extension of the exported video? To save the video in the format you want, you just need to add the appropriate `PathComponent` when creating the video URL: ```swift let videoURL = manager.temporaryDirectory.appendingPathComponent("tmp.mov") ``` See an example in the [sample](https://github.com/Banuba/ve-sdk-ios-integration-sample/tree/main/Example/Example/ViewController.swift#L238). See all the formats supported for the video export [here](guide_export.md). ## I want to change the order of masks, video effects or filters. The SDK allows to reorder masks and filters in the way you need. To achieve this, use the `preferredLutsOrder` and `preferredMasksOrder` properties: ``` swift let config = VideoEditorConfig() // Sorting for the record screen config.recorderConfiguration.recorderEffectsConfiguration.preferredLutsOrder = [ "egypt", "norway", "japan" ... ] config.recorderConfiguration.recorderEffectsConfiguration.preferredMasksOrder = [ "XYScanner", "Background" ... ] // Sorting for the post processing screen config.filterConfiguration.preferredLutsOrder = [ "byers", "sunset", "vinyl" ... ] config.filterConfiguration.preferredMasksOrder = [ "XYScanner", "Background" ... ] config.filterConfiguration.preferredVideoEffectOrderAndSet = [ VisualEffectApplicatorType.acid, VisualEffectApplicatorType.dvCam ... ] ``` ## Is it possible to disable the Trim screen? It is possible to turn off the trimmer screen after the camera screen. The trimmer screen will still be accessible after importing media files from the gallery. To disable it, just change the `supportsTrimRecordedVideo` property to `false` in the `FeatureConfiguration` entity: ``` swift func createVideoEditorConfig() -> VideoEditorConfig { var config = VideoEditorConfig() ... // Default is false config.featureConfiguration.supportsTrimRecordedVideo = true ... return config } ``` ## Is it possible to disable the transition effects? Transitions are visual effects applying to the segue between two videos. They are provided with the Banuba Video Editor SDK **by default**. To disable or enable transitions, set the `useTransitions` flag inside the `FeatureConfiguration` class to false or true respectively: ``` swift /// Allows you to use transition effects between videos /// Defaults is true public var useTransitions: Bool ``` Example: ``` swift let config = VideoEditorConfig() config.featureConfiguration.useTransitions = true ``` :::note Transition effects are not being played if the closest video (either to the left or to the right of the transition icon) is very short. ::: ## How can I convert one or several still images to a video programmatically? If you would like to create a video from UIImage instances without opening the Video Editor, you can use our API SDK tailored for solutions with the custom built UI, namely the `exportSlideshowImages` method of the `VEExport` class. ## Is it possible to store localization strings in a file other than Localizable.strings? Sometimes other 3rd party dependencies overwrite the `Localizable.strings` file stored in the app bundle during compilation. In such cases it is also possible to store the localization strings in the `Banuba.strings` file. ## How to change the default animation (exposure view) shown after tapping on the camera preview? Create a class conforming to `ExternalViewControllerFactory` that implements the `exposureViewFactory` property. In the following example the default view factory `DefaultExposureViewFactory` provided by the SDK is used: ```swift class ExampleViewControllerFactory: ExternalViewControllerFactory { var exposureViewFactory: AnimatableViewFactory? var musicEditorFactory: MusicEditorExternalViewControllerFactory? var countdownTimerViewFactory: CountdownTimerViewFactory? init() { exposureViewFactory = DefaultExposureViewFactory() } } ``` Pass the instance of your factory to the `externalViewControllerFactory` argument of `BanubaVideoEditor`: ```swift let videoEditorSDK = BanubaVideoEditor( token: ..., configuration: ..., // highlight-add-next-line + externalViewControllerFactory: ExampleViewControllerFactory() ) ``` ## How to change the default countdown timer shown on the camera screen? Create a class conforming to `ExternalViewControllerFactory` that implements the `countdownTimerViewFactory` property. In the following example the view factory that provides the built-in class `CountdownView` is implemented: ```swift class ExampleViewControllerFactory: ExternalViewControllerFactory { var exposureViewFactory: AnimatableViewFactory? var musicEditorFactory: MusicEditorExternalViewControllerFactory? var countdownTimerViewFactory: CountdownTimerViewFactory? init() { countdownTimerViewFactory = CountdownTimerViewControllerFactory() } /// Example countdown timer view factory for Recorder countdown animation class CountdownTimerViewControllerFactory: CountdownTimerViewFactory { func makeCountdownTimerView() -> CountdownTimerAnimatableView { let countdownView = CountdownView() countdownView.frame = UIScreen.main.bounds countdownView.font = countdownView.font.withSize(102.0) countdownView.digitColor = .white return countdownView } } } ``` Pass the instance of your factory to the `externalViewControllerFactory` argument of `BanubaVideoEditor`: ```swift let videoEditorSDK = BanubaVideoEditor( token: ..., configuration: ..., // highlight-add-next-line + externalViewControllerFactory: ExampleViewControllerFactory() ) ``` ## How to change the global color appearance (palette) of the SDK? Create an instance of `VideoEditorColorsPalette` with the desired colors and assign it to `VideoEditorConfig`: ```swift var config = VideoEditorConfig() config.setupColorsPalette( VideoEditorColorsPalette( primaryColor: .white, secondaryColor: .black, accentColor: .white, effectButtonColorsPalette: EffectButtonColorsPalette( defaultIconColor: .white, defaultBackgroundColor: .clear, selectedIconColor: .black, selectedBackgroundColor: .white ), addGalleryItemBackgroundColor: .white, addGalleryItemIconColor: .black, timelineEffectColorsPalette: TimelineEffectColorsPalette.default ) ) ``` ## How to change the video preview resizing mode at Recording Screen Starting from the 1.35.0 version of the SDK the `RecorderConfiguration` has the property called `previewScalingMode` with two possible options `aspectFill` and `aspectFit`: ```swift /// Specifies options of scaling the video preview from camera at recorder screen public enum RecorderPreviewScalingMode { /// Fill entire preview screen with camera video feed case aspectFill /// Fit camera video in the screen so that entire video is always visible case aspectFit } var config = VideoEditorConfig() config.recorderConfiguration.previewScalingMode = .aspectFit ``` By default the `aspectFill` option is used. It provides the same preview scaling behaviour as in previous releases of the SDK. ## How to collect logs when I encounter an issue? If you encounter a crash or other issue and are unsure how to provide logs to the support team, follow steps provided below: 1. Connect your iPhone to your Mac via USB or Wi-Fi. 2. Open Xcode → go to Window → Devices and Simulators. 3. In the list, select your device. 4. In the right panel, click Open Console. 5. You will now see all system and app logs in real time. 6. To view only logs for your app, use the Filter by process field and enter the app’s Bundle ID. Once you’ve collected the logs, copy them into a separate text file and send it to the [support team](https://www.banuba.com/support) for further investigation. --- ## Video Templates on iOS Templates let users create stunning videos quickly and easily using predefined sets of effects, transitions, and music. All it takes to make a shareable piece is changing the placeholders. With templates, even people who are new to video editing or just lack time can make impressive content in minutes.       :::important The ```Video Templates``` is not enabled by default. Contact Banuba representatives to know more. ::: ## Launch Video Templates Use the ```.videoTemplates``` entry point in ```VideoEditorLaunchConfig``` to launch the Video Editor SDK from Video templates. ```swift let launchConfiguration = VideoEditorLaunchConfig( entryPoint: .videoTemplates, hostController: self, animated: true ) videoEditorSDK.presentVideoEditor( withLaunchConfiguration: launchConfiguration, completion: nil ) ``` ## Setup Templates Templates source is set via the `catalogSource` property of `videoTemplatesConfiguration`. Two options are available. ### Static Catalog #### `.staticCatalog` The same approach as the previous `url` property: ```swift let catalogURL = URL(string: "https://.../response.json")! config.videoTemplatesConfiguration.catalogSource = .staticCatalog(catalogURL) ``` #### `.templateStore` Load templates from Banuba Templates Service. This option allows to publish new templates created in Template Builder as well. :::important Requires a `clientSecret` value provided by Banuba representative. ::: ```swift config.videoTemplatesConfiguration.catalogSource = .templateStore( TemplateStoreConfiguration( clientSecret: "YOUR_TEMPLATE_STORE_CLIENT_SECRET" ) ) ``` ### Migration from `url` to `catalogSource` Replace `url` assignments with `.staticCatalog(url)` or switch to `.templateStore(...)`. ```swift // Before config.videoTemplatesConfiguration.url = URL(string: "https://…/response.json")! // After — static catalog config.videoTemplatesConfiguration.catalogSource = .staticCatalog( URL(string: "https://…/response.json")! ) // After — templateStore config.videoTemplatesConfiguration.catalogSource = .templateStore( .init(environment: .production, clientSecret: "…") ) ``` ## Template Builder       :::important This feature is currently available on iOS only (starting from version 1.51.3). *** Access requires a specific license token feature. Please contact your Banuba representative to enable it. *** Template Builder requires `.templateStore` set in `videoTemplatesConfiguration.catalogSource`. ::: Template Builder allows users to create and publish custom video templates with transitions, effects, music, and text. Published templates appear in the templates gallery for all users in your app. The Banuba Video Editor SDK presents Template Builder modally on top of your host screen — you control when to open it (for example, from a "Create template" button). ```swift // 1. Create SDK instance let videoEditor = BanubaVideoEditor( token: "YOUR_LICENSE_TOKEN", configuration: config, externalViewControllerFactory: nil ) // 2. Open Template Builder videoEditor.presentTemplatesCreator( from: hostViewController, animated: true, completion: nil ) ``` #### Key Features - **No-Code Template Creation:** Client teams build branded video templates in minutes without engineering support. - **Flexible Parameters:** Define music, transitions, clip lengths, FX, text, and metadata tags. - **Fillable Media Slots:** Set dedicated media placeholders for end-users to insert their own videos. - **Publish & Distribute:** Publish templates so they appear in the gallery for all app users. #### Terms of Use URL The Template Builder includes a confirmation step before a template is published. At this step, the user sees a message similar to: > *«By publishing, you confirm that your content complies with the Terms of Use and does not infringe third-party rights.»* The **Terms of Use** link in that message leads to a page where you define the full legal terms that apply to content created and published by your team members using the Template Builder. The URL must point to a publicly accessible web page and **must be valid and reachable**. ```swift var config = VideoEditorConfig() guard let termsURL = URL(string: "https://example.com/terms") else { fatalError("Invalid Terms of Use URL") } config.videoTemplatesConfiguration .templateBuilderConfiguration .termsOfUseURL = termsURL ``` ## Localized Strings Add or override the following keys in your `Localizable.strings` to customize Templates and Template Builder UI text: ```swift // MARK: - Templates "BanubaVideoEditor.VideoTemplates.serviceUnavailableTitle" = "Service is not available"; "BanubaVideoEditor.VideoTemplates.noTemplatesFound" = "No templates found"; ``` --- ## AI Clipping on React Native The ```AI Clipping``` feature automates the video creation process by leveraging the power of artificial intelligence. The neural network transforms raw input into ready-to-post videos with various transitions, effects, and a precise music match. Here is how users can interact with it: 1. User selects clips and music. People can choose their desired clips and accompanying music within the app. 2. AI trims the videos. The AI algorithm intelligently trims the selected clips to match the tempo and rhythm of the chosen track. 3. AI adds various effects. AI Clipping enhances the content by adding a variety of effects to create visually stunning content. 4. User exports, edits, or regenerates the clip. Upon completion, users have the flexibility to export the video as is, make further edits, or regenerate the clip for a fresh perspective. 5. Regardless of the user’s editing skills, with the help of Auto Cut, everyone can get a stunning video within seconds. ## Supported music providers 1. [Soundstripe](audio_browser_guide.md#soundstripe) 2. [Banuba Music](audio_browser_guide.md#banuba-music) :::note Please contact Banuba representatives to know more about using the ```Banuba music``` with ```AI Clipping```. ::: ## Usage ### Setup configuration Specify instance of ```AiClipping``` in ```FeaturesConfig``` builder: :::important Contact Banuba representatives to get trial keys for ```audioDataUrl``` and ```audioTracksUrl``` use in production. ::: ```typescript private featuresConfig = new FeaturesConfigBuilder() .setAiClipping(new AiClipping({ audioDataUrl: "...", audioTracksUrl: "..." }) ) ... .build(); ``` ### Launch AI Clipping :::note Video creation with AI Clipping is available on Gallery screen by default. ::: For better experience we added new entry point to `VideoEditorPlugin` for opening AI Clipping as a separate mode. In this scenario the user starts from the gallery screen and is taken to AI Clipping screen after selecting media. ```typescript videoEditor.openFromAiClipping(LICENSE_TOKEN, this.featuresConfig) .then(response => { this.handleVideoExport(response); }) .catch(e => { this.handleSdkError(e); }); ``` --- ## Audio Browser on React Native ```Audio Browser``` - a specific module and set of screens that include the built-in support of browsing and applying audio content within the Video Editor. The user does not leave the SDK while using audio. :::note Banuba does not deliver audio content for the Video Editor SDK. The Video Editor can apply audio files stored on the device. The SDK is not responsible for downloading audio content except for [Soundstripe](https://www.soundstripe.com/). ::: Audio Browser is a specific module that allows to browse, play and apply audio content within video editor. It supports 3 sources for audio content: 1. Soundstripe - includes built in integration with Soundstripe API. 2. Banuba Music - includes built in integration with Banuba Music 3. My Library - includes audio content available on the user's device ## Usage ### Soundstripe [Soundstripe](https://www.soundstripe.com/) is a service for providing the best audio tracks for creating video content. Your users will be able to add audio tracks while recording or editing video content. :::note The feature is not activated by default. Please contact Banuba representatives to know more about using this feature. ::: Specify the instance of ```AudioBrowser``` in ```FeaturesConfig``` builder with Soundstripe source: ```typescript private config = new FeaturesConfigBuilder() .setAudioBrowser(AudioBrowser.fromSource({ source: AudioBrowserSource.soundstripe, params: null })) ... .build(); ``` ### Banuba Music Over 35 GB of royalty-free tracks available from within the Video Editor SDK. Your users could check them out through an inbuilt music browser and legally include them in their content. :::note The feature is not activated by default. Please contact Banuba representatives to know more about using this feature. ::: Specify the instance of ```AudioBrowser``` in ```FeaturesConfig``` builder with Banuba Music source and params: ```typescript private config = new FeaturesConfigBuilder() .setAudioBrowser(AudioBrowser.fromSource({ source: AudioBrowserSource.banubaMusic, params: null })) ... .build(); ``` ### My Library ```My Library``` is a default implementation in AudioBrowser . It allows the user to apply audio that is available on a device. Specify the instance of ```AudioBrowser``` in ```FeaturesConfig``` builder with local source: ```typescript private config = new FeaturesConfigBuilder() .setAudioBrowser(AudioBrowser.fromSource({ source: AudioBrowserSource.local, params: null })) ... .build(); ``` --- ## Camera screen on React Native ## Usage Specify instance of ```CameraConfig``` in ```FeaturesConfig``` builder: ```typescript final featuresConfig = new FeaturesConfigBuilder() .setCameraConfig(new CameraConfig({ supportsBeauty: false, supportsColorEffects: false, supportsMasks: false, recordModes: [RecordMode.video, RecordMode.photo], autoStartLocalMask: null })) ... .build() ``` ### Options - ```supportsBeauty``` - Determines whether the camera supports beauty effect. Default value is ```true```. - ```supportsColorEffects``` - Determines whether the camera supports color effects. Default value is ```true```. - ```supportsMasks``` - Determines whether the camera supports visual effects. Default value is ```true```. - ```recordModes``` - Determines which recording modes are supported. Default value is ```[RecordMode.video, RecordMode.photo]```. - ```autoStartLocalMask``` - Determines whether the camera starts with preselected mask. Default value is ```null``` --- ## Closed Captions on React Native AI Captions are a textual representation of the audio within a media file. Over 80% of videos played on mobile devices don’t have sound turned on. This means many forms of content (e.g. skits, monologues, educational clips, etc.) will be skipped if there are no subtitles. But making captions by hand is tedious. AI-generated subtitles solve this issue, as they are created and placed automatically. The users can then edit the text as well as change its style and color. [AWS Transcribe service](https://docs.aws.amazon.com/transcribe/) is used to generate captions. ## Supported languages - Arabic - English - Mandarin - Spanish - Portuguese ## Usage Specify instance of ```Captions``` in ```FeaturesConfig``` builder: :::important A trial option for AI Captions Please contact Banuba representatives before use in production. ::: ```typescript private featuresConfig = new FeaturesConfigBuilder() .setCaptions( new Captions({ uploadUrl: "https://internal.transcribe.banuba.net", transcribeUrl: "https://rest.internal.transcribe.banuba.net/transcribe/v1/status", apiKey: "CheiYaaphoK6eungecheec4eingeik9shaijiech" }) ) ... .build(); ``` --- ## Cover Screen on React Native Cover image screen allows users to pick any frame of video as image or choose an image from gallery. ## Usage Specify instance of ```ConfigConfig``` in ```FeaturesConfig``` builder: ```typescript final featuresConfig = new FeaturesConfigBuilder() .setCoverConfig( new CoverConfig({ supportsCoverScreen: false, }) ) ... .build() ``` ### Options - ```supportsCoverScreen``` - Determines whether the Cover screen supports. Default value is ```true```. --- ## Draft Configuration on React Native Drafts are enabled by default, asks the user to save a draft before leave any VideoEditor screen. ## Usage Specify instance of ```DraftsConfig``` in ```FeaturesConfig``` builder to change drafts configuration: ```typescript private featuresConfig = new FeaturesConfigBuilder() .setDraftsConfig(DraftsConfig.fromOption({ option: DraftsOption.auto })) ... .build(); ``` ### Options - ```DraftsOption.askToSave``` - drafts enabled, asks the user to save a draft - ```DraftsOption.auto``` - drafts enabled, saved by default without asking the user - ```DraftsOption.closeOnSave``` - drafts enabled, asks the user to save a draft without export - ```DraftsOption.disable``` - disabled drafts --- ## Editor screen on React Native ## Usage Specify instance of ```EditorConfig``` in ```FeaturesConfig``` builder: ```typescript final featuresConfig = new FeaturesConfigBuilder() .setEditorConfig(new EditorConfig({ enableVideoAspectFill: false, supportsColorEffects: false, supportsVisualEffects: false, supportsVoiceOver: false, supportsAudioEditing: false, supportPhotoEditing: false, supportsStickersOnVideo: false, })) ... .build() ``` ### Options - ```enableVideoAspectFill``` - Fill video aspect on the editor screen while playback. Default value is ```true```. - ```supportsColorEffects``` - Determines whether the editor supports color effects. Default value is ```true```. - ```supportsVisualEffects``` - Determines whether the editor supports visual effects. Default value is ```true```. - ```supportsVoiceOver``` - Determines whether the editor supports voice over. Default value is ```true```. - ```supportsAudioEditing``` - Determines whether the editor supports audio editing. Default value is ```true```. - ```supportPhotoEditing``` - Requires the [pe-sdk-react-native](https://www.npmjs.com/package/pe-sdk-react-native) plugin. Determines whether the editor supports photo editing flow in Banuba Photo Editor. Default value is ```false```. - ```supportsStickersOnVideo``` - Determines whether the editor supports stickers on video. Default value is ```true```. --- ## Editor V2 on React Native ## Overview With the new interface, better controls, and additional quality of life improvements, making stunning videos is easier and more fun than ever. Design and user experience principles are constantly evolving. To keep up with the latest developments and best practices, our team has completely redesigned the Video Editor SDK to be as convenient and enjoyable as possible. ## Usage Set the ```.setEditorV2``` to true in the ```FeaturesConfigBuilder```: ```typescript private featuresConfig = new FeaturesConfigBuilder() .setEditorV2(true) .build(); ``` --- ## Export media on React Native ## Overview Video Editor SDK allows to export a number of video files with various resolutions and other configurations. Video is exported as `.mp4` for Android and `.mov` for IOS file. Refer to our main docs [Android](https://docs.banuba.com/ve-pe-sdk/docs/android/guide_export) and [IOS](https://docs.banuba.com/ve-pe-sdk/docs/ios/guide_export) to learn more about media export in the Video Editor. ## Implement export flow :::note Default implementation exports single video file with auto quality(based on device hardware capabilities). ::: Create a new instance of `ExportData` to export 2 videos with `HD` and `auto` qualities: ```javascript private exportData = new ExportData({ exportedVideos: [ new ExportedVideo({ fileName: 'export_hd', videoResolution: VideoResolution.fhd1080p, }), new ExportedVideo({ fileName: 'export_auto', videoResolution: VideoResolution.auto, }), ], }); ``` Next, specify it in the [start method](https://github.com/Banuba/ve-sdk-react-native/blob/master/example/src/App.tsx#L125) of the Video Editor: ```diff videoEditor.openFromCamera( LICENSE_TOKEN, this.featuresConfig, + this.exportData ) ``` ## Use AVC codec You can specify `H264(AVC_PROFILES)` by setting `false` to `useHevcIfPossible`. ```diff private exportData = new ExportData({ exportedVideos: [ new ExportedVideo({ fileName: 'export_hd', videoResolution: VideoResolution.fhd1080p, + useHevcIfPossible: false }), ], }) ``` ## Add watermark Watermark is not added to exported video by default. Add watermark to assets catalog in [Android](https://github.com/Banuba/ve-sdk-react-native/tree/master/example/android/app/src/main/assets/) and [IOS](https://github.com/Banuba/ve-sdk-react-native/tree/master/example/ios/VideoEditorReactNativeExample/Images.xcassets/) module. :::important Plugin support watermark image in the ```.png``` format. ::: ### Android Add assets folder in the [android](https://github.com/Banuba/ve-sdk-react-native/tree/master/example/android/app/src/main/assets/) module and provide the ```sourceSets``` in the [build.gradle](https://github.com/Banuba/ve-sdk-react-native/tree/master/example/android/app/build.gradle) android app module: ```diff android { ... + sourceSets { + main { + assets.srcDirs += 'src/main/assets' + } } ... } ``` ### IOS Add watermark to [Images.xcassets](https://github.com/Banuba/ve-sdk-react-native/tree/master/example/ios/VideoEditorReactNativeExample/Images.xcassets/). ### Example Provide watermark to ```Export Data``` instance: ```diff private exportData = new ExportData({ exportedVideos: [ new ExportedVideo({ fileName: 'export_hd', videoResolution: VideoResolution.fhd1080p, }), ], + watermark: new Watermark({ + imagePath: 'watermark.png', + alignment: WatermarkAlignment.topLeft, + }), }); ``` --- ## Banuba Photo Editor React Native ## Overview [Banuba Photo Editor SDK](https://www.banuba.com/photo-editor-sdk) allows you to quickly add photo functionality and effects into your mobile app. ## Usage ### License Before you commit to a license, you are free to test all the features of the SDK for free. The trial period lasts 14 days. To start it, [send us a message](https://www.banuba.com/photo-editor-sdk#form). We will get back to you with the trial token. Feel free to [contact us](https://www.banuba.com/support) if you have any questions. ## Installation Run in Terminal to install Photo Editor React Native plugin ```sh npm install pe-sdk-react-native ``` ## Integration guide Please follow our [Integration Guide](https://docs.banuba.com/ve-pe-sdk/docs/react/pe_integration) to complete full integration. ## Launch Set Banuba license token [within the app](https://github.com/Banuba/ve-sdk-react-native/blob/master/example/src/App.tsx#L8) ### Android 1. Make sure variable ```ANDROID_SDK_ROOT``` is set in your environment or configure ```sdk.dir```. 2. Run ```npm run android``` in Terminal to launch the sample app on a device or launch the app in IDE i.e. Intellij, VC, etc. ### iOS 1. Install CocoaPods dependencies. Open ```ios``` directory and run in terminal ```pod install```. 2. Open **Signing & Capabilities** tab in Target settings and select your Development Team. 3. Run ```npm run ios``` in Terminal to launch the sample on a device or launch the app in IDE i.e. XCode, Intellij, VC, etc. ## Dependencies | | Version | |--------------|:-------:| | Yarn | 4.6.0 | | React Native | 0.75.2 | | Android | 6.0+ | | iOS | 15.0+ | --- ## Integration Guide on React Native This guide helps to complete full Photo Editor SDK integration. ## Configuration ### IOS :::important Please make sure Bridge Header file exits in ios folder. ::: #### Add specs to Podfile Add the following specs at the top of your [Podfile](https://github.com/Banuba/pe-sdk-react-native/blob/master/example/ios/Podfile) ``` platform :ios, '15.0' source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/Banuba/specs.git' source 'https://github.com/sdk-banuba/banuba-sdk-podspecs.git' ``` #### Add permissions Specify the required iOS permissions used by the SDK in your [Info.plist](https://github.com/Banuba/pe-sdk-react-native/blob/master/example/ios/PeSdkReactNativeExample/Info.plist) ``` NSPhotoLibraryUsageDescription This app requires access to the photo library. ``` ## Limit processor architectures on Android Banuba Photo Editor on Android supports the following processor architectures - ```arm64-v8a```, ```armeabi-v7a```, ```x86-64```. Please keep in mind that each architecture adds extra MBs to your app. To reduce the app size you can filter architectures in your ```app/build.gradle file```. ```groovy ... defaultConfig { ... // Use only ARM processors ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' } } ``` --- ## Stickers on React Native Stickers are interactive objects (gif images) that can be added to the video recording. ## Giphy Video Editor uses [Giphy service](https://developers.giphy.com/docs/api/) for loading stickers. Any sticker effect is a GIF file. ## Usage Specify instance of ```GifPickerConfig``` in ```FeaturesConfig```: :::important To use stickers in your project you need to request personal [Giphy API key](https://support.giphy.com/hc/en-us/articles/360020283431-Request-A-GIPHY-API-Key) ::: ```typescript private featuresConfig = new FeaturesConfigBuilder() .setGifPickerConfig(new GifPickerConfig({ giphyApiKey: "...", mode: GiphyMode.search, ids: ["...","..."] })) ... .build(); ``` --- ## Banuba Video Editor React Native ## Overview Build apps like TikTok and Videoshop faster with the Banuba [Video Editor SDK](https://www.banuba.com/video-editor-sdk-api-social-media-app) for React Native. With an extensive feature set, simple integration process, and user-friendly interface, it is a comprehensive toolkit that will bring your app to the level of industry giants. Its flexibility allows you to only pick the features that you need, optimizing the app’s download size and license costs. Banuba Video Editor React Native plugin offers [certain features that few competitors do](https://www.banuba.com/blog/best-video-editor-sdks-compared), including high-quality Face AR masks and AI video editing tools. Features: - Recording - Trimming & merging - Sound track editing - Hands-free mode - Transition effects - Color filters (LUTs) - Text, picture, and GIF overlays - 3D masks - Beauty effects - Picture-in-picture (Duets) - AR filters - AI clipping - AI video generation - AI subtitles - Royalty-free music library - Music provider integration And more Refer to the documentation for more details: - [Android](https://docs.banuba.com/ve-pe-sdk/docs/android/requirements-ve/) - [iOS](https://docs.banuba.com/ve-pe-sdk/docs/ios/requirements) Video Editor SDK **works offline**, and doesn’t send, store, or process any user information, making it **compliant with GDPR and other data protection regulations**. ## Usage ### License [Start a 14-day free trial](https://www.banuba.com/video-editor-sdk#form) and see how the Video Editor SDK React Native plugin works. No credit card information is needed. Feel free to [contact us](https://www.banuba.com/support) if you have any questions regarding this plugin. ## Installation Run in Terminal to install Video Editor React Native plugin ```sh npm install video-editor-react-native ``` ## Integration guide Please follow our [Integration Guide](https://docs.banuba.com/ve-pe-sdk/docs/react/ve_integration) to complete full integration. ## Launch Set Banuba license token [within the app](https://github.com/Banuba/ve-sdk-react-native/blob/master/example/src/App.tsx#L24) ### Android 1. Make sure variable ```ANDROID_SDK_ROOT``` is set in your environment or configure ```sdk.dir```. 2. Run ```npm run android``` in Terminal to launch the sample app on a device or launch the app in IDE i.e. Intellij, VC, etc. ### iOS 1. Install CocoaPods dependencies. Open ```ios``` directory and run in terminal ```pod install```. 2. Open **Signing & Capabilities** tab in Target settings and select your Development Team. 3. Run ```npm run ios``` in Terminal to launch the sample on a device or launch the app in IDE i.e. XCode, Intellij, VC, etc. ## Dependencies | | Version | |--------------|:-------:| | Yarn | 3.6.1 | | React Native | 0.83.0 | | Android | 8.0+ | | iOS | 15.0+ | --- ## Integration Guide on react Native(React) This guide helps to complete full Video Editor SDK integration. ## Configuration ### Android #### Add Activity Add ```VideoCreationActivity``` in [AndroidManifest.xml](https://github.com/Banuba/ve-sdk-react-native/blob/master/example/android/app/src/main/AndroidManifest.xml#L30) file. ``` xml ``` ### IOS :::important Please make sure Bridge Header file exits in ios folder. ::: #### Add specs to Podfile Add the following specs at the top of your [Podfile](https://github.com/Banuba/ve-sdk-react-native/blob/master/example/ios/Podfile) ``` platform :ios, '15.0' source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/Banuba/specs.git' source 'https://github.com/sdk-banuba/banuba-sdk-podspecs.git' ``` #### Add permissions Specify the required iOS permissions used by the SDK in your [Info.plist](https://github.com/Banuba/ve-sdk-react-native/blob/master/example/ios/VideoEditorReactNativeExample/Info.plist) ``` NSAppleMusicUsageDescription This app requires access to the media library NSCameraUsageDescription This app requires access to the camera. NSMicrophoneUsageDescription This app requires access to the microphone. NSPhotoLibraryUsageDescription This app requires access to the photo library. ``` ## Add AR effects [Banuba Face AR SDK](https://www.banuba.com/facear-sdk/face-filters) product is used on camera and editor screens for applying various AR effects while making video content. 1. Android - add effects to the project by the path [android/app/src/main/assets/bnb-resources/effects](https://github.com/Banuba/ve-sdk-react-native/blob/master/example/android/app/src/main/assets/). 2. iOS - add the effect to resource folder ```bundleEffects```. Make sure to select the "Copy items if needed" and "Create folder references" checkboxes while adding effects to the ```bundleEffects``` folder. ## Disable Face AR SDK ### Android Set the ```ENABLE_FACE_AR``` flag to the [gradle.properties](https://github.com/Banuba/ve-sdk-react-native/blob/master/example/android/gradle.properties#L42): ```diff ... newArchEnabled=true # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. hermesEnabled=true + ENABLE_FACE_AR=false ``` ### IOS Set the environment ```ENABLE_FACE_AR``` flag the the [PodFile](https://github.com/Banuba/ve-sdk-react-native/blob/master/example/ios/Podfile#L15): ```diff ... prepare_react_native_project! + ENV['ENABLE_FACE_AR'] = 'false' linkage = ENV['USE_FRAMEWORKS'] if linkage != nil Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green use_frameworks! :linkage => linkage.to_sym end ... ``` ## Enable Android Photo Picker Set the ```ENABLE_GALLERY``` flag to the [gradle.properties](https://github.com/Banuba/ve-sdk-react-native/blob/master/example/android/gradle.properties):: ```diff + ENABLE_GALLERY=false ``` ## Limit processor architectures on Android Banuba Video Editor on Android supports the following processor architectures - ```arm64-v8a```, ```armeabi-v7a```, ```x86-64```. Please keep in mind that each architecture adds extra MBs to your app. To reduce the app size you can filter architectures in your ```app/build.gradle file```. ```groovy ... defaultConfig { ... // Use only ARM processors ndk { abiFilters 'armeabi-v7a', 'arm64-v8a' } } ``` ## Customizations ### Usage Create instance of the ```FeaturesConfig``` to apply various Video Editor configurations. Pass the ```FeaturesConfig``` instance to any Video Editor [start method](https://github.com/Banuba/ve-sdk-react-native/blob/master/example/src/App.tsx#L125). For example: ```typescript private featuresConfig = new FeaturesConfigBuilder() .setAudioBrowser(AudioBrowser.fromSource({ source: AudioBrowserSource.local, params: null }) ) .build(); ``` ```typescript const videoEditor = new VideoEditorPlugin(); videoEditor.openFromCamera(LICENSE_TOKEN, this.featuresConfig) .then(response => { this.handleVideoExport(response); }) .catch(e => { this.handleSdkError(e); }); ``` --- ## Video Duration on React Native ```VideoDurationConfig``` is responsible for customizing video recording durations. ## Usage Specify instance of ```VideoDurationConfig``` in ```FeaturesConfig```: ```typescript private featuresConfig = new FeaturesConfigBuilder() .setVideoDurationConfig(new VideoDurationConfig({ maxTotalVideoDuration: 180.0, videoDurations: [180.0, 60.0] })) .build(); ``` --- ## Video Templates on React Native Templates let users create stunning videos quickly and easily using predefined sets of effects, transitions, and music. All it takes to make a shareable piece is changing the placeholders. With templates, even people who are new to video editing or just lack time can make impressive content in minutes.       :::important The ```Video Templates``` is not enabled by default. Contact Banuba representatives to know more. ::: ## Launch Video Templates ```typescript videoEditor.openFromTemplates(LICENSE_TOKEN, this.featuresConfig) .then(response => { this.handleVideoExport(response); }) .catch(e => { this.handleSdkError(e); }); ``` ## Setup Custom Templates :::important Use this method if you have an agreement with Banuba for the delivery of additional templates and have received the corresponding URL. By default, the SDK is delivered with predefined configuration to load Banuba templates. ::: Two options are available. ### By URL ```typescript const featuresConfig = new FeaturesConfigBuilder() .setTemplatesConfig(new TemplatesConfig({ url: YOUR_URL })) ... .build(); ``` ### By secret key :::important Requires a `secret` key provided by your Banuba representative. ::: ```typescript const featuresConfig = new FeaturesConfigBuilder() .setTemplatesConfig(new TemplatesConfig({ secret: 'YOUR_SECRET_KEY' })) ... .build(); ``` ## Template Builder       :::important This feature is currently available on iOS only (starting from version 1.51.3). *** Access requires a specific license token feature. Please contact your Banuba representative to enable it. ::: Template Builder allows users to create custom video templates with transitions, effects, music, and text. Others can use these as starting points by replacing the media placeholders. ### Key Features - **No-Code Template Creation:** Client teams build branded video templates in minutes without engineering support. - **Flexible Parameters:** Define music, transitions, clip lengths, FX, text, and metadata tags. - **Fillable Media Slots:** Set dedicated media placeholders for end-users to insert their own videos. ### Launch Template Builder ```typescript final featuresConfig = new FeaturesConfigBuilder() .setTemplatesConfig(new TemplatesConfig({ url: YOUR_URL, enableBuilder: true, termsOfUseUrl: })) ... .build() ``` ### Terms of Use URL The Template Builder includes a confirmation step before a template is published. At this step, the user sees a message similar to: > *«By publishing, you confirm that your content complies with the Terms of Use and does not infringe third-party rights.»* The **Terms of Use** link in that message leads to a page where you define the full legal terms that apply to content created and published by your team members using the Template Builder. Setting this URL ensures that your organisation’s usage policies, IP guidelines, and content restrictions are clearly communicated to anyone who can publish templates. The link must point to a publicly accessible web page (e.g. your company’s Terms of Use or a dedicated policy document) and the URL **must be valid and reachable**. --- ## Build a Banuba Video Editor with AI **In about an hour, you'll have a working Banuba Video or Photo Editor running in a local demo app on your laptop.** You don't need to write code yourself. You'll use the **Claude desktop app** (in its **Code** mode), tell it what to build in plain English, and Banuba's official **AI Skills** will guide it to set up the SDK correctly. **Difficulty:** ●●○○○ Beginner-friendly **Time:** ~1 hour **Works on:** Mac and Windows. :::tip First time doing something like this? That's exactly who this guide is for. You'll go through five prep steps and five build steps. Every step ends with three checks so you always know whether you're on track: - **Where am I?** What you just did. - **Is it OK?** A clear finish line you can verify before moving on. - **What's going on?** A short explanation of why this step matters. If anything doesn't match what you see on your screen, you're not stuck, just **ask your AI agent (Claude Code, ChatGPT, Claude.ai, or Gemini) in plain English what to do.** That's a normal part of the process. Stuck? Jump to [Troubleshooting](#troubleshooting). ::: ## What you'll have at the end A working demo you can show to stakeholders, hand to a developer, or use to sharpen product requirements. Concretely: - **A starter app** in your `banuba-demo` folder, ready to open in Android Studio or Xcode. - **A running Banuba editor** on your simulator or emulator, where you can trim clips, apply filters, add AR effects, and export the result. - **SDK-aligned demo code** generated with Banuba's official AI Skill instructions, released with every SDK update so the agent stays aligned with the latest integration flow. ### Two common scenarios * **No app yet?** This guide assumes this scenario. You'll create a new starter app from scratch with help from the AI agent. * **Already have an app?** Point the agent at your existing project folder and ask it to add Banuba Video Editor or Photo Editor as a module inside your app. ## Who this guide is for | If you're a… | This guide helps you… | |---|---| | **Application owner** evaluating Banuba | See a working demo before committing engineering resources | | **Product manager** scoping a video or photo editing feature | Validate the user flow and understand what is required for a working integration | | **Project manager** planning the integration | Estimate scope, prepare the right inputs, and brief engineering more clearly | | **Developer** with the integration ticket | Get SDK-specific answers faster, avoid long documentation searches, and start from guided integration steps instead of a blank project | ## How it works Three pieces work together: 1. **Banuba SDK**. The Video Editor or Photo Editor that runs inside your app. Requires a Banuba license key. Get a free trial with no payment required. 2. **AI coding agent**. A tool that can create and edit code based on your instructions. We recommend **Claude Code**. **Codex** and **Qwen Code** can also work; see [Alternative agents](#alternative-agents). 3. **Banuba's AI Skills**. Official instructions that teach the agent how to integrate Banuba SDKs correctly. Released with every SDK update. You install the agent once, install Banuba's AI Skills with **one short command** (the only command-line step in this guide), and then ask in plain English: > Set up a Banuba Video Editor demo for iOS and/or Android. The agent creates the project and guides you through the build. To get there, you'll use **Terminal** a few times at the beginning. Don't worry, you won't need to understand coding commands. You'll only copy commands from this guide, paste them into Terminal, and press Enter. :::tip What's "Terminal"? Terminal is a small text-window app that already comes with your computer. On Mac, it is called **Terminal**. On Windows, you can use **PowerShell (as admin)** instead. You type a command, press Enter, and the command runs. That's all you need for this guide. If something goes wrong, nothing in this guide is designed to change your personal files or system settings without you seeing it first. You can stop at any time and jump to [Troubleshooting](#troubleshooting). ::: --- ## Prep - 15 minutes :::tip Never used Terminal before? Terminal is the text-window app where you type commands. - **Mac:** Press `⌘ + Space`, type `Terminal`, press Enter. - **Windows:** Press the Windows key, type `Terminal` or `PowerShell`, press Enter. You type a command, press Enter, and the command runs. That's all you need for this guide. ::: ### 1. Get a Banuba license key Without a license key, the SDK won't run, even in a trial build. Get yours first. 1. Open [Video Editor SDK for Android & iOS](https://www.banuba.com/video-editor-sdk#form) (the page will scroll directly to the trial form). 2. Click the **Get a Free Trial** button. No payment information is required. 3. Fill in the short form (name, email). 4. **You'll receive a license key token immediately on the next page.** It's a long alphanumeric string - copy it and save it somewhere safe (a password manager or a private note). :::note Don't worry, submitting the form gives you the token right away. You won't get a sales call before you can try the SDK. ::: **Where am I?** You have your Banuba license key saved somewhere safe. **Is it OK?** Yes, if you have a long alphanumeric token in hand. **What's going on?** The token authorizes the SDK to run during your trial. ### 2. Pick your target platform Choose one platform to start with. You can repeat the process for another platform later. | Platform | What you need | Pick if… | |---|---|---| | **Android** | Android Studio (free), about 30 GB of free disk space | You do not have a Mac, or you want the simplest first setup | | **iOS** | A Mac and Xcode | You are targeting iPhone or iPad first | | **Flutter** | Flutter SDK + Android Studio and/or Xcode | You want one codebase for iOS and Android | | **React Native** | Node.js + Android Studio and/or Xcode | You already have a React Native app | :::warning Using an older Mac? Banuba SDKs currently require **Xcode 15 or higher**, which needs **macOS Ventura 13.5 or newer**. If your Mac runs an older macOS, you can still build for **Android** without limitations. ::: ### 3. Install the platform toolchain Install only the toolchain for the platform you picked. - **Android Studio:** [https://developer.android.com/studio](https://developer.android.com/studio) - **Xcode:** Open the App Store on Mac, search for Xcode, and install it - **Flutter:** [https://docs.flutter.dev/get-started/install](https://docs.flutter.dev/get-started/install) - **React Native:** [https://reactnative.dev/docs/environment-setup](https://reactnative.dev/docs/environment-setup) **Where am I?** You have the IDE for your platform installed. **Is it OK?** Open it once and accept any first-launch prompts. On Android Studio, let it download the default Android SDK when it asks. **What's going on?** This is the visual app where you'll run your demo at the end. **Done when:** you can run a sample project on a simulator or emulator. ### 4. Install Node.js Node.js is required to run the Banuba AI Skills installer in the next section. 1. Open [https://nodejs.org](https://nodejs.org) and click the **LTS** download button for your OS. 2. Run the installer. **Accept the default options**, they're correct. 3. When the installer finishes, **close the Node.js installer window**. You won't type any commands in it. Now open your Terminal (Mac) or PowerShell-as-admin (Windows) and run: ```bash node --version ``` :::tip Heads up for Windows users If you opened Terminal before installing Node.js, close it and reopen it (still as admin). Windows needs a fresh Terminal window to "see" the new install. ::: **Where am I?** You have Node.js installed. **Is it OK?** Terminal returns a version like `v20.x.x` or higher. **What's going on?** Node.js gives you `npm` and `npx` - small tools we'll use to install the Banuba AI Skills in the next steps. **Done when:** Terminal returns a version number, for example `v20.x.x` or higher. ### 5. Install Claude Code desktop app The Claude desktop app is the visual app where you'll do all the actual building. It includes a **Code** mode that wraps Claude Code's full capabilities in a friendly chat interface - no Terminal required. 1. Download the Claude desktop app from [https://claude.ai/download](https://claude.ai/download) (Mac and Windows versions are available). 2. Install it, sign in with your Anthropic account, and open it once to confirm it launches. 3. In the top-left of the app window, click the **Code** tab. You should see a clean dashboard with **New session**, **Routines**, **Customize**, and **More** in the left sidebar. **Where am I?** The Claude desktop app is installed and you can see the Code tab. **Is it OK?** The Code tab opens without errors. A model selector (e.g., Sonnet 4.6) is visible at the bottom-right. **What's going on?** This is the surface where you'll chat with the AI agent, **pick the project folder**, and watch the build happen. You won't touch Terminal again after one more step. --- ## ✅ Prep checkpoint You're ready to build when **all four** of these are true: - Node.js installed: `node --version` returns a version number - Android Studio / Xcode / Flutter / React Native tooling launches without errors - The Claude desktop app launches and the Code tab is visible - You have your Banuba license key saved somewhere you can paste from later If any of these fails, don't push through - **ask the Claude desktop app, ChatGPT, Claude.ai, or Gemini what's wrong** in plain English. Paste the error message you see. They'll usually identify the issue in one round. --- ## Build - five steps to a working Video and Photo Editor ### 1. Create a project folder *(1 min)* Create an empty folder where Claude will build your demo. **Use your normal file manager, no command line.** **Mac (Finder):** 1. Open **Finder**. 2. Press `⇧ + ⌘ + H` to go to your home folder (the one named after your username). 3. Choose **File → New Folder**, name it `banuba-demo`. **Windows (File Explorer):** 1. Open **File Explorer**. 2. Navigate to your user folder (e.g., `C:\Users\YOUR-NAME\`). 3. Right-click in an empty area → **New → Folder**, name it `banuba-demo`. **Where am I?** An empty `banuba-demo` folder exists in your home folder. **Is it OK?** You can see the folder in Finder / File Explorer. **What's going on?** This is where Claude will write your demo app. Remember the path - you'll point both the Claude desktop app and Android Studio / Xcode at it. ### 2. Install Banuba's AI Skills *(2 min)* This is the **last command-line step in the entire guide.** One short command, paste-and-press-Enter. After this, you're back in the visual Claude desktop app for everything else. **Mac (Terminal):** 1. Press `⌘ + Space`, type `Terminal`, press Enter. 2. Paste this single line and press Enter: ```bash npx skills add Banuba/ai-skills -a claude-code ``` **Windows (PowerShell as administrator):** 1. Press **Win + R**, type `powershell`, then press **Ctrl + Shift + Enter** to launch PowerShell **as administrator**. Click **Yes** on the permission prompt. Without admin rights, the installer can be blocked by Windows. 2. Paste this single line and press Enter: ```bash npx skills add Banuba/ai-skills -a claude-code ``` **When the interactive list of skills appears**, the installer is asking you which ones to install: - **↑ / ↓ arrows** - move between skills - **Space** - select / deselect a skill (a checkmark appears next to selected ones) - **a** - select all (Recommended) - **Enter** - confirm ✅ **Recommendation: select all skills.** They're small, and you get maximum flexibility: Video Editor, Photo Editor, and inline docs lookup. Press `a`, then Enter. The installed skills include: - `build-video-editor` - helps set up Banuba **Video Editor** SDK - `build-photo-editor` - helps set up Banuba **Photo Editor** SDK - `explain-video-editor-photo-editor-docs` - helps the agent answer SDK documentation questions The skills are downloaded into a hidden `.claude/skills/` folder inside your project. **Where am I?** Banuba's AI Skills are installed on your computer, where the Claude desktop app can find them. **Is it OK?** Terminal printed a confirmation listing the skills you selected. No red error text. **What's going on?** You just finished the only command-line step. From now on, everything happens inside the Claude desktop app: chat input, slash commands, file changes - all visual. You can close the Terminal / PowerShell window now. You won't need it again. :::tip Want to try skipping Terminal entirely? Open the Claude desktop app → **Code** tab → **New session**. In the chat, type: "Install Banuba's AI Skills from the `Banuba/ai-skills` repo so I can use the build-video-editor skill." If Claude installs them and confirms success, you can skip the Terminal step above. If it can't (you'll see an error or a message that it lacks the tools), no problem - fall back to the one-line command above. Either path lands you in the same place. ::: :::warning Windows users - a quick note on command syntax If you ever need to chain Windows commands together, **PowerShell / CMD don't accept `&&`** (it's a Unix-only operator). Use separate lines, or `;` in PowerShell. This guide gives you commands one at a time so you won't hit this, but if you find other guides online that use `&&`, that's why it fails on Windows. ::: ### 3. Open the Claude desktop app and point it at your folder *(1 min)* Back in the visual world. From here, you live in the Claude desktop app. 1. Open the **Claude desktop app** and click the **Code** tab in the top-left. 2. At the bottom of the chat area, click **Select folder…** and choose your `banuba-demo` folder. 3. Click **New session** in the left sidebar. **Where am I?** A new Claude Code session is open, pointed at your `banuba-demo` folder. The chat input is ready for you to type. **Is it OK?** The folder name appears near the chat input (next to the **Local** label). The model selector at the bottom-right shows the model you're using, for example, **Sonnet 4.6**. **What's going on?** Because the session is pointed at `banuba-demo`, the agent can see Banuba's AI Skills you installed in Step 2 and will use them automatically when you ask it to build. ### 4. Ask the agent to build *(10–30 min)* In the chat input, type one of the prompts below. Replace `[Android]` / `[iOS]` with your platform, and `[paste your token]` with your real Banuba license key. **For Video Editor:** ``` /build-video-editor Set up a Banuba Video Editor demo for [Android]. Banuba license key: [paste your token] ``` **For Photo Editor:** ``` /build-photo-editor Set up a Banuba Photo Editor demo for [iOS] with photo effects and AR filters. Banuba license key: [paste your token] ``` :::tip Start typing `/` in the chat input - the desktop app will list available slash commands, including the Banuba ones, so you don't have to remember them. ::: :::tip Expect Claude to ask you questions, that's normal. It might ask things like: - "Which export resolution do you want?" - "Should the editor open the camera by default, or open the gallery?" - "May I create this file? May I run this command?" Answer in plain English. If you're not sure, use one of these replies: - "Use the defaults." - "Pick what you recommend for a first demo." - "Yes, you can create that file." / "Yes, you can run that command." If a question is confusing, ask Claude to explain it in simpler words. You can write: `Explain this in simpler words. I'm not technical.` ::: Claude Code may also ask for permission to create files, edit files, or run commands. Review the request and approve it if it matches the setup you asked for. In Claude Code, the **Accept edits** button is where you confirm file changes. **Where am I?** Claude has scaffolded a starter project and written the integration code into your `banuba-demo` folder. **Is it OK?** Claude reports that the build is finished and tells you how to run the app. There are no red error messages. The folder now contains real project files, such as `gradle`, `app`, `ios`, or similar names depending on your platform. **What's going on?** Banuba AI Skills guided Claude on which starter template to use and how to configure the SDK. Your Banuba license key has been added to the project configuration so the demo can run. ### 5. Run it *(5 min)* 🎯 **You're done with Claude Code for now.** The final step happens in Android Studio or Xcode. #### 5a. Open the project in your IDE Open the IDE that matches your platform: - **Android, Flutter, React Native (Android side):** Android Studio - **iOS, Flutter (iOS side), React Native (iOS side):** Xcode In the IDE, choose **File → Open**, then navigate to your `banuba-demo` folder. If you created the folder in the default location, it is usually here: **Mac:** `/Users/YOUR-NAME/banuba-demo` **Windows:** `C:\Users\YOUR-NAME\banuba-demo` Select the folder and click **Open**. #### 5b. Wait for the project to load The first load may take a few minutes. The IDE needs to download dependencies and prepare the project before you can run it. - **Android Studio:** Look at the bottom status bar. It may say **Gradle sync in progress**. Wait until sync finishes. This usually takes 1–5 minutes the first time. - **Xcode:** Wait for **Indexing** and package resolution to finish. Let Xcode finish preparing the project before clicking Run. **Where am I?** The IDE is showing your project files on the left and source code in the middle. **Is it OK?** The status bar says sync, indexing, or package resolution is finished. There are no red error messages at the bottom. **What's going on?** The IDE is downloading and preparing the libraries your project needs, including Banuba SDK dependencies. #### 5c. Create or select a virtual device To run the demo, you need a virtual phone on your laptop. - For Android, this is called an **emulator**. - For iOS, this is called a **simulator**. **Android Studio - Android emulator:** 1. Click **Tools → Device Manager**. 2. Click **Create device**. 3. Choose a recent phone, such as **Pixel 9**. 4. Click **Next**. 5. Choose a recent system image, such as **API 34 / Android 14**. 6. Click **Download** if needed. 7. Click **Next**, then **Finish**. **Xcode - iOS simulator:** 1. Open **Window → Devices and Simulators**. 2. Check that at least one iPhone simulator is available. 3. If no simulator is listed, click **+** and add a recent iPhone, such as **iPhone 16**. **Where am I?** You have at least one virtual device available in your IDE. **Is it OK?** The device appears in the device dropdown near the **Run** button. **What's going on?** When you click Run, the IDE will install your demo app onto this virtual device. #### 5d. Click Run At the top of the IDE, find the green **Run** button. 1. Select your virtual device in the dropdown next to the Run button. 2. Click **Run**. The first build usually takes a few minutes. After that, the simulator or emulator opens and your Banuba editor launches inside it. **Where am I?** The Banuba editor is running on a virtual phone on your laptop. **Is it OK?** You can record or import media, trim, apply filters or effects, add AR effects, and export the result. **What's going on?** This is a working demo of Banuba Video Editor or Photo Editor SDK running inside a starter app. It is suitable for stakeholder review, product scoping, and developer handoff before production integration. --- ## 🎉 You now have a working Banuba editor. Congrats! The app running on your simulator or emulator is a real, end-to-end Banuba editor. You can: - Record or import a video or photo - Trim clips, apply filters, and add AR effects - Export the result **What this is:** A working demo. The integration code is real, the SDK is the real Banuba SDK, and the editor is functional. **What this is not yet:** Your production app. Right now, it is a starter app with Banuba Video Editor or Photo Editor inside. ## From here, you can start shaping the demo into your real product. Go back to your **Claude Code session**. It should still be open. Keep talking to the agent and ask for small changes, one step at a time: - Add a music library to the editor. - Remove the beauty filters tab. - Make export the primary action. - Add a sign-in screen before the editor opens. - Wire this editor into a new screen inside my existing app at `[path-to-your-app]`. Each prompt moves the demo closer to your product. Repeat as many times as you need. :::tip Not sure what to ask next? Ask Claude directly: - "I want this editor to feel like a modern short-form video editor. What should I change first?" - "What is the simplest way to add my logo to this editor?" - "What should I customize before showing this demo to stakeholders?" ::: --- ## What to do next | If you're a… | Do this | |---|---| | **Application owner** | Record a short screen capture and align stakeholders on what matters before scoping production work. | | **Product manager** | Iterate by re-prompting the agent. For example: "Add a music library," "Remove the beauty filters tab," or "Make export the primary action." | | **Project manager** | Use the [handoff template](#developer-handoff-template) below to brief engineering clearly. | | **Developer** | Use inline docs lookup when needed: `/explain-video-editor-photo-editor-docs How does export work?` Then connect the editor to the real app flow. | ### Developer handoff template Paste this into a ticket or Slack message: > > > **Banuba Video/Photo Editor demo is ready for engineering review** > > **What's done:** > A working demo was scaffolded with Banuba's `[build-video-editor / build-photo-editor]` AI Skill for `[platform]`. > > **Source:** > `[path or repo link]` > > **License key:** > Stored in `[vault or secure location]`. > Do not paste the license key directly into the ticket or Slack thread. > > **Engineering, please review and complete:** > > - Review the generated integration against our app architecture > - Replace the trial license with the correct production token when appropriate > - Wire the editor into `[feature / screen / user flow]` > - Confirm required permissions, media access, and export behavior > - Run our security, privacy, accessibility, and QA review > - Confirm the integration matches Banuba's latest SDK documentation > > **References:** > > - Banuba SDK documentation: [https://docs.banuba.com/ve-pe-sdk](https://docs.banuba.com/ve-pe-sdk) > - For inline documentation lookups in Claude Code, use: `/explain-video-editor-photo-editor-docs [your question]` --- ## Troubleshooting Most issues come from one of these: the one Terminal step was skipped or blocked, the Claude desktop app isn't pointed at the right folder, or no virtual device exists yet. | Symptom | Cause | Fix | |---|---|---| | `npx: command not found` (during the one Terminal step) | Node.js not installed, or Terminal hasn't refreshed | Install Node.js from [https://nodejs.org](https://nodejs.org). **Close and reopen Terminal** (Windows: as admin) and try the command again. | | Windows: `'&&' is not a valid statement separator` | A command used `&&`, which Windows PowerShell / CMD doesn't accept | Run each command on its own line. Or use `;` in PowerShell. | | Windows: installer says "access denied" or "permission denied" | Terminal wasn't launched as administrator | Close Terminal. Press `Win + R` → type `powershell` → press **Ctrl + Shift + Enter** to relaunch as admin. | | You asked Claude to install the skills, but it said it couldn't | The agent may not have the system-level tools to install skills in your setup | Fall back to the one-line Terminal command in Step 2. Reliable on every machine. | | `/build-video-editor` doesn't appear in the slash command list | Claude desktop app session isn't pointed at the folder where the skills were installed | In the desktop app, click **Select folder…** at the bottom and pick `banuba-demo`. Start a new session. | | Banuba AI Skills installed, but Claude says it can't find them | The session may have started before the skills were installed | Close the session, then start a new session pointed at `banuba-demo`. Skills are picked up at session start. | | IDE opens the project, but Run button is greyed out / "no device selected" | No virtual device created yet | **Android Studio:** Tools → Device Manager → Create Virtual Device. **Xcode:** Window → Devices and Simulators → add a simulator. Then pick it in the Run dropdown. | | Build done, but the simulator won't launch | Platform toolchain isn't fully set up, or Gradle/Pod sync didn't finish | Wait for sync to fully finish, then click Run again. If still failing, open Build → Build output and read the error. Paste it back into the Claude desktop app. | | License error at runtime | Token pasted wrong or trial expired | Request a fresh key from [banuba.com/video-editor-sdk](https://www.banuba.com/video-editor-sdk#form). Then tell Claude: "Update the Banuba license key in this project." Paste the new key only when Claude asks. | | Where's my project folder? | You don't remember where `banuba-demo` was created | Check `~/banuba-demo` (Mac) or `C:\Users\YOUR-NAME\banuba-demo` (Windows). Or use Finder/File Explorer's search. | | App builds, but camera or media access doesn't work | Permissions missing or blocked | In the Claude desktop app, ask: "Check camera, microphone, and media permissions for this Banuba editor demo." | | Export doesn't work | Export config or simulator limitation | In the Claude desktop app, ask: "Check why export isn't working and verify the export configuration." | **Still stuck?** [Open an issue](https://github.com/Banuba/ai-skills/issues) or [contact Banuba support](https://www.banuba.com/contact). Include: - Your target platform: Android, iOS, Flutter, or React Native - Your SDK version, if known - The command or prompt you used - The full error message or screenshot - Whether you are using a simulator, emulator, or real device Do **not** paste your Banuba license key into public issues, Slack channels, or support screenshots. --- ## Reference ### All available skills | Skill | What it does | Example prompt | |---|---|---| | `build-video-editor` | Sets up Banuba Video Editor SDK end-to-end | "Set up a short-form video editor with trimming, filters, AR effects, and export." | | `build-photo-editor` | Sets up Banuba Photo Editor SDK end-to-end | "Set up a photo editor with effects, filters, and AR features." | | `explain-video-editor-photo-editor-docs` | Answers questions using Banuba Video Editor and Photo Editor SDK documentation | "How do I change the export resolution?" | The build skills include starter templates for **Android, iOS, Flutter, and React Native**. The agent can detect the platform from your prompt or project structure. The skills run locally inside your AI coding agent. You do not need to paste long SDK documentation into every prompt, and the skills are kept aligned with Banuba SDK releases. ### Alternative agents {#alternative-agents} | Agent | Install command (use in Terminal once) | |---|---| | **Claude Code** *(recommended)* | `npx skills add Banuba/ai-skills -a claude-code` | | Codex | `npx skills add Banuba/ai-skills -a codex` | | Qwen Code | `npx skills add Banuba/ai-skills -a qwen-code` | Skills are installed into the agent-specific skills folder, such as `.claude/skills/`, `.codex/skills/`, or `.qwen/skills/`. ### No agent setup? **Use the LLM-ready documentation files instead:** - [llms.txt](../llms.txt) - shorter version for quick context - [llms-full.txt](../llms-full.txt) - complete version for deeper analysis You can paste these files into ChatGPT, Claude.ai, Gemini, or another LLM. This option is slower and will not create or edit files on your computer, but it is useful for a first look, product scoping, or asking documentation questions without setting up an AI coding agent. ### Glossary - **Agent skill** - Packaged instructions that teach an AI coding agent how to complete a specific task correctly. - **License key** - The Banuba credential that unlocks the SDK. It is required to run the SDK, including trial builds. - **npx** - A tool that comes with Node.js. It can run an installer command without permanently installing that installer on your computer. In this guide, you use it to install Banuba AI Skills. - **Repo (GitHub repo)** - A folder of code hosted on GitHub. For this guide, you do not need to open GitHub manually - the install command fetches the required files for you. - **Simulator / emulator** - A virtual phone running on your laptop. It lets you test an app without using a real device. - **Slash command** - A command inside an AI agent starting with `/`, like `/build-video-editor`. - **Terminal** - The text-window app where you type commands. On Mac, it is called Terminal. On Windows, you can use Terminal or PowerShell. - **IDE** - An app developers use to open, run, and edit projects. Examples include Android Studio, Xcode, Visual Studio Code, and WebStorm.