---
title: "How to Apply Filter Effects to Video using VidEffects library on Android"
description: "Learn about the benefits and limitations of VidEffects for video editing on Android."
url: "https://img.ly/blog/how-to-apply-filter-effects-to-video-using-videffects-on-android/"
type: "blog"
date: "2022-05-24"
author: "Neslihan"
tags: ["How-To","Video Editing","Android","Android App Development","Mobile App Development","Push2Medium","Tutorial"]
---

> This is the markdown version of [How to Apply Filter Effects to Video using VidEffects library on Android](https://img.ly/blog/how-to-apply-filter-effects-to-video-using-videffects-on-android/). For all pages in one file, see [llms-full.txt](https://img.ly/llms-full.txt). For an index of all available pages, see [llms.txt](https://img.ly/llms.txt).

---

Video manipulation is a complex topic on Android because there is no out-of-the-box support from the Android SDK, and using FFmpeg requires not just a very elaborate setup but having to climb a steep learning curve to learn its CLI commands.

As an aside, we have also put together how-to blogs to elaborate on other video manipulation operations like merging still images to form videos, [compressing and resizing videos](https://img.ly/blog/working-with-large-video-and-image-files-on-ios-with-swift.md), or background removal.

The [VidEffects](https://github.com/krazykira/VidEffects) library is much faster to set up than FFmpeg, and it works by applying effects to `GLSurfaceView`. This blog post will demonstrate how to apply Filter effects to a video in an Android app using the VidEffects library.

VidEffects does support storing videos on the disk, but it has limitations in this regard which we will discuss in a moment.

Before we begin, keep in mind that the VidEffects library differentiates between **Effects** and **Filters**. As an example, we will apply both and discuss the crucial difference between the two.

Without much further ado, let's start coding.

## Create a VidEffects Example App

Create a **New Project** with an Empty Activity in Android Studio. Select _Kotlin_ as the language (or Java if you wish), and set \*\*Minimum SDK to API 21.

You can also download the final code from [GitHub](https://github.com/numerative/videffects_sample).

### Add Dependency

In your module-level **build.gradle** (app/build.gradle) file add the latest VidEffects dependency.

```groovy
dependencies {
    ...

    implementation "com.github.krazykira:videffects:1.1.1"

    ...
}
```

Next, enable `viewBinding` by adding the following lines within the `android{}` closure.

```groovy
android {
    ...
    buildFeatures {
        viewBinding true
    }
}
```

By using View Binding, we can avoid the `findViewById()` method.

Click **Sync Now** to sync the project with gradle files.

### Add Video Asset File

Place the sample video file in **app/src/main/assets/** directory. Ideally, your app will load the video file from disk – but to avoid complexity, we are placing the video in the assets directory.

![directory_tree_android_video-effect](https://blog.img.ly/2022/05/directory_tree_android_video-effect.jpg)

## Create a Layout

![screen_no_filter-1](https://blog.img.ly/2022/05/screen_no_filter-1.jpg)

Create the above layout with a `VideoSurfaceView`, three Filter buttons, and one Reset Button.

Replace your **activity_main.xml**\`s code with the following.

```xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <com.sherazkhilji.videffects.view.VideoSurfaceView
        android:id="@+id/mVideoSurfaceView"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        app:layout_constraintTop_toTopOf="parent" />
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/wrapper"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/mVideoSurfaceView">
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/bwButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Black and White"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/grainButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Grain"
            app:layout_constraintStart_toEndOf="@id/bwButton"
            app:layout_constraintTop_toTopOf="parent" />
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/duotoneButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="DuoTone"
            app:layout_constraintStart_toEndOf="@id/grainButton"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/resetButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Reset"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/wrapper" />
</androidx.constraintlayout.widget.ConstraintLayout>
```

## Initialize the video

Before initializing the video, set up an instance of the Binding class to use it within the Activity.

### Setup View Binding

Add the following code in **MainActivity.kt** before calling `setContentView()`.

If you do not wish to use View Binding and instead prefer using `findViewById()`, skip to the next step _Initializing the Sample Video_.

```kotlin
private lateinit var binding: ActivityMainBinding
class MainActivity : AppCompatActivity() {
		private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        ...
    }
    companion object {
        private const val TAG = "MainActivity"
    }
}
```

The `ActivityMainBinding` class is auto-generated. If it did not get auto-generated, then sync the project with the gradle file from **File > Sync Project with Gradle Files.**

Next, pass the _root view_ to the `setContentView()`.

```kotlin
class MainActivity : AppCompatActivity() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        setContentView(binding.root)
    }
}
```

### Initializing the Sample Video

Next, declare and initialize the `MediaPlayer` variable.

```kotlin
class MainActivity : AppCompatActivity() {
    ...
    private lateinit var mMediaPlayer: MediaPlayer
        override fun onCreate(savedInstanceState: Bundle?) {
            ...
            mMediaPlayer = MediaPlayer()
    }
}
```

Then open the video file from our assets directory and pass it as the data source to the Media Player.

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    ...
    try {
        val afd = assets.openFd("sample.mp4")
        mMediaPlayer.setDataSource(
            afd.fileDescriptor,
            afd.startOffset, afd.length
        )
    } catch (e: Exception) {
        Log.e(TAG, e.message, e)
    }
}
```

Now, all that is remaining is to initialize the `VideoSurfaceView`.

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
        ...
        binding.mVideoSurfaceView.init(mMediaPlayer, NoEffectFilter())
    }
```

Your app should run. While the buttons still do not work, we will `setOnClickListeners()` next.

![screen_no_filter-2](https://blog.img.ly/2022/05/screen_no_filter-2.jpg)

## Apply VidEffects Effects

The VidEffects library offers [multiple effects](https://github.com/krazykira/VidEffects#supported-effects), but we will be applying three: Black and White, Grain, and Duotone.

In **MainActivity**'s `onCreate()`, copy the following code to setup all the `setOnClickListeners`.

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    ...
    //Black and White Effect
    binding.bwButton.setOnClickListener {
        binding.mVideoSurfaceView.shader = BlackAndWhiteEffect()
    }
    //Grain Filter
    binding.grainButton.setOnClickListener {
        val grainFilter = GrainFilter(10, 10)
        grainFilter.setIntensity(0.5f)
        binding.mVideoSurfaceView.filter = grainFilter
    }
    //Duotone Effect
    binding.duotoneButton.setOnClickListener {
        binding.mVideoSurfaceView.shader =
            DuotoneEffect(Color.BLUE, Color.YELLOW)
    }
    //Reset with AutoFixFilter
    binding.resetButton.setOnClickListener {
        binding.mVideoSurfaceView.filter = NoEffectFilter()
    }
}
```

Run the app.

![screen-bw-duo-grain](https://blog.img.ly/2022/05/screen-bw-duo-grain.png)

## Difference Between Effects and Filters

As mentioned before, Effects and Filters are two separate functions in the VidEffects library.

_Effects_ are temporary, view-only overlays that cannot be stored on the disk. _Filters_ can be viewed and stored on the disk. Unfortunately, a majority of the overlays offered by VidEffects are [Effects](https://github.com/krazykira/VidEffects/tree/master/videffects/src/main/java/com/sherazkhilji/videffects) and therefore only useful for playback only. At the time of writing this article, only three [Filters](https://github.com/krazykira/VidEffects/tree/master/videffects/src/main/java/com/sherazkhilji/videffects/filter) are available.

## Limitations

One of the biggest limitations of this library, as mentioned above, is that the majority of the effects provided by the library are just view-only.

Moreover, to save videos with filters, the app must target `minSdk 23` at least or use FFmpeg.

Many of these Effects do not have an intensity parameter and therefore we cannot fine-tune these effects.

## Alternative

If you are looking for an easy-to-integrate solution that overcomes these limitations, take a look at IMG.LY's [VideoEditor SDK](https://img.ly/docs/vesdk/android/introduction/getting_started?utm_source=imgly&utm_medium=blog&utm_campaign=howtos). It provides more than 60 high-quality adjustable filters out-of-the-box. Moreover, you can easily add [custom filters](https://img.ly/docs/vesdk/android/features/filters/#add-custom-lut-filters?utm_source=imgly&utm_medium=blog&utm_campaign=howtos) using LUT files. VideoEditor SDK works for Android SDK version 21 and above and thus targets more devices.

If the purpose is to apply effects during the playback, the VidEffects library is a solid and free open-source solution. While it handles all the complex video editing, developers will have to spend some time developing the layout.

### Thanks for reading! Let us know what you think on [Twitter](https://twitter.com/imgly), or stay in the loop with our [Newsletter](https://photoeditorsdk.us13.list-manage.com/subscribe?u=dc9f652839dbb620d14d6d28d&id=04a306e4b2).

---

## More Resources

- **[IMG.LY Website](https://img.ly/index.md)** - Creative editing SDKs for photo, video, and design
- **[Documentation](https://img.ly/docs/cesdk/)** - CE.SDK developer documentation
- **[Contact Sales](https://img.ly/forms/contact-sales.md)** - Get a custom quote. A public JSON API accepts the request directly, no account or key needed. Ask your user for consent and their details first.
