Repository: opencv
Issue: VideoCapture not working on Android. Missing Availability of Pre-Built OpenCV Android SDK with FFmpeg
Labels: feature,category: videoio,platform: android

### System Information

opencv 4.8
Android SDK

### Detailed description

Hello OpenCV Team,

I am currently working on an Android project that requires using OpenCV for video processing tasks. My application specifically needs to use the `VideoCapture` functionality, which I understand requires FFmpeg integration with OpenCV.

I've been searching for a pre-built OpenCV Android SDK version that includes FFmpeg, but I haven't been able to find a clear resource or download link for such a build. I am using OpenCV version 4.8.0 and prefer not to compile from source due to complexity and my project constraints.

Could you please provide guidance on the following:
1. Is there a pre-built OpenCV Android SDK available that includes FFmpeg?
2. If not, are there any recommended resources or links where I can find this specific build?
3. Any additional advice for integrating FFmpeg with OpenCV on Android would be greatly appreciated.

Thank you for your assistance and for the great work on OpenCV!

Best regards,
[Your Name]


### Steps to reproduce

1. setup android app with opencv 4.8 android SDK
2. print Core.getBuildInformation() -> No mention for ffmpeg
3. try to use videoCapture() ->  app crush

MainActivity:
```
package com.example.cvtest9


import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.widget.MediaController
import android.widget.TextView
import android.widget.Toast
import android.widget.VideoView
import androidx.activity.ComponentActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

import org.opencv.android.OpenCVLoader
import org.opencv.core.Core
import org.opencv.core.Mat
import org.opencv.dnn.Dnn
import org.opencv.videoio.VideoCapture
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream

class MainActivity : ComponentActivity() {




    // Copy Yolo Files
    private fun copyFileFromAssets(assetFileName: String, destinationFilePath: String) {
        val assetManager = this.assets
        val inputStream = assetManager.open(assetFileName)
        val outputStream = FileOutputStream(destinationFilePath)
        inputStream.copyTo(outputStream)
        inputStream.close()
        outputStream.flush()
        outputStream.close()
    }

    // Check if file exists before trying to pass it to opencv's videoCapture
    private fun checkIfFileExists(filePath: String): Boolean {
        val file = File(filePath)
        return if (file.exists()) { // THIS LINE IS PASSING AS EXPECTED. filePath IS CORRECT
            Log.d("File Check", "The file exists: $filePath")
            Toast.makeText(this, "The file exists: $filePath", Toast.LENGTH_LONG).show()
            true
        } else {
            Log.d("File Check", "The file does not exist: $filePath")
            Toast.makeText(this, "The file does not exist: $filePath", Toast.LENGTH_LONG).show()
            false
        }
    }

    // get absolute path of the video file to pass to opencv's videoCapture
    private fun moveFileFromRawToApp(): String {
        val ins: InputStream = resources.openRawResource(R.raw.test_video)
        val outFile = getAppSpecificDirectory("test_video.mp4")
        val out = FileOutputStream(outFile)
        val outputStream = ByteArrayOutputStream()
        var buffer = ByteArray(1024)
        var size = ins.read(buffer, 0, 1024)
        while (size >= 0) {
            outputStream.write(buffer, 0, size)
            size = ins.read(buffer, 0, 1024)
        }
        ins.close()
        buffer = outputStream.toByteArray()
        out.write(buffer)
        out.close()
        return outFile.absolutePath
    }


    private fun getAppSpecificDirectory(filename: String): File {
        val file = File(baseContext.filesDir, filename)
        if (!file.exists()) {
            file.createNewFile()
        }
        return file
    }

    private fun openFileByOpenCV(absFilePath: String) {
        val videoCapture = VideoCapture()

        if (videoCapture.open(absFilePath)) { // NOTICE! THIS LINE IS FAILING. IT SEEMS THAT IM MISSING DEPENDENCIES FOR THE NATIVE CODE OF THIS JAVA WRAPPER FUNCTION
            Toast.makeText(this, "OpenCV worked", Toast.LENGTH_LONG).show()
            // Continue with frame processing
            // ...
        } else {
            Toast.makeText(this, "Failed to open video file", Toast.LENGTH_LONG).show()
        }
    }


    // TODO: Process Frames in thread
    private fun processVideo() {
        // Launch a coroutine in IO dispatcher for background tasks
        val absFilePath = moveFileFromRawToApp()

        if(checkIfFileExists(absFilePath)){
            openFileByOpenCV(absFilePath)
        }
    }

    private fun processFrame(frame: Mat) {
        Log.d("ProcessFrame", "Processing a frame")

        // TODO: frame processing code
        // ...
    }


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Set the content view to your layout
        setContentView(R.layout.main)

        // Video View
        val videoView: VideoView = findViewById(R.id.videoView)
        val uri: Uri = Uri.parse("android.resource://" + packageName + "/" + R.raw.test_video)
        videoView.setVideoURI(uri)
        videoView.start()
        val mediaController = MediaController(this)
        mediaController.setAnchorView(videoView)
        videoView.setMediaController(mediaController)


        // Text View
        val textView: TextView = findViewById(R.id.helloWorldTextView)
        textView.text = "Hello World from OpenCV!"

        // OpenCV init
        if (!OpenCVLoader.initDebug()) {
            Log.d("OpenCV", "Internal OpenCV library not found. Using OpenCV Manager for initialization")
            OpenCVLoader.initDebug()
        } else {
            Log.d("OpenCV", "OpenCV library found inside package. Using it!")
            // print build info
            val buildInformation = Core.getBuildInformation()
            Log.d("OpenCV Build Info", buildInformation)
            // Copy YOLO model files from assets to internal storage
            val cfgFilePath = filesDir.absolutePath + "/yolov3.cfg"
            val weightsFilePath = filesDir.absolutePath + "/yolov3.weights"

            copyFileFromAssets("yolov3.cfg", cfgFilePath)
            copyFileFromAssets("yolov3.weights", weightsFilePath)

            // Load the YOLO model
            val net = Dnn.readNetFromDarknet(cfgFilePath, weightsFilePath)

            // Process video frame by frame
            processVideo() // Call processVideo method

        }
    }
}

```

gradle:

```
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}

android {
    namespace = "com.example.cvtest9"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.example.cvtest9"
        minSdk = 26
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary = true
        }
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }


    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    ...

    ...
    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
        resources.pickFirsts.add("lib/arm64-v8a/libc++_shared.so")
        resources.pickFirsts.add("lib/x86/libc++_shared.so")
        resources.pickFirsts.add("lib/x86_64/libc++_shared.so")
        resources.pickFirsts.add("lib/armeabi-v7a/libc++_shared.so")
    }
}

dependencies {
   ....

    implementation(project(":opencv"))
}
```

### Issue submission checklist

- [X] I report the issue, it's not a question
- [X] I checked the problem with documentation, FAQ, open issues, forum.opencv.org, Stack Overflow, etc and have not found any solution
- [X] I updated to the latest OpenCV version and the issue is still there
- [X] There is reproducer code and related data files (videos, images, onnx, etc)