bytedeco/javacv

how to use hw accelerator with FFMpegFrameRecorder

Open

#2,046 opened on Jun 23, 2023

View on GitHub
 (6 comments) (0 reactions) (0 assignees)Java (1,583 forks)batch import
enhancementhelp wantedquestion

Repository metrics

Stars
 (6,985 stars)
PR merge metrics
 (No merged PRs in 30d)

Description

I try to use mobile hardware accelerator with FFMpegFrameRecorder, but software only is used :

private fun initFFMpegRecorder() { ffmpeg_link = File(StorageUtils.createPhoneVideoFileName(context))

    yuvImage = Frame(1920, 1080, Frame.DEPTH_UBYTE, 2)
    Log.i(LOG_FFMPEG, "create yuvImage")

    ffMpegFrameRecorder = FFmpegFrameRecorder(
        ffmpeg_link,
        1920,
        1080,
        1
    )
    ffMpegFrameRecorder?.format = "mkv"

    ffMpegFrameRecorder?.sampleRate = sampleAudioRateInHz
    ffMpegFrameRecorder?.audioBitrate = 128 * 1024
    ffMpegFrameRecorder?.audioCodec = avcodec.AV_CODEC_ID_AAC

    ffMpegFrameRecorder?.setVideoMetadata("rotate", "90")

    ffMpegFrameRecorder?.frameRate = 30.toDouble()
    ffMpegFrameRecorder?.videoBitrate = 6 * 1000 * 1024
    ffMpegFrameRecorder?.gopSize = 30
    ffMpegFrameRecorder?.isInterleaved = true
    ffMpegFrameRecorder?.videoCodec = avcodec.AV_CODEC_ID_H264
    ffMpegFrameRecorder?.pixelFormat = avutil.AV_PIX_FMT_YUV420P

    ffMpegFrameRecorder?.videoCodecName = "h264_mediacodec"

    ffMpegFrameRecorder?.timestamp = 1000 * (System.currentTimeMillis() - startTime)
    ffMpegFrameRecorder?.setVideoOption("preset", "ultrafast")
    ffMpegFrameRecorder?.setVideoOption("tune", "zerolatency")

    Log.i(
        LOG_FFMPEG,
        "recorder video initialize success"
    )

    audioRecordRunnable = AudioRecordRunnable()
    audioThread = Thread(audioRecordRunnable)
    runAudioThread = true
    Log.i(
        LOG_FFMPEG,
        "recorder audio initialize success"
    )
}

fun startRec() { initFFMpegRecorder()

        try {
            val avCodec: AVCodec? = avcodec.avcodec_find_encoder_by_name("h264_mediacodec")
            if (avCodec != null) {
                Log.i(
                    "SUPPORT_ENCODER_TELEPHONE",
                    "avCodec != null, " + avCodec.name().getString()
                        .toString() + "/ " + avCodec.long_name().getString()
                )
            } else {
                Log.i("SUPPORT_ENCODER_TELEPHONE", "avCodec == null")
            }

            ffMpegFrameRecorder?.start()
            startTime = System.currentTimeMillis()
            recording = true
            audioThread?.start()
            isRecordingVideo.set(true)
            Log.d(LOG_FFMPEG, "FFMpeg launched")
        } catch (e: FFmpegFrameRecorder.Exception) {
            e.printStackTrace()
        }

}

i can get rawVideo here (i am using Camera2 API and ImageReader) like this :

imageReader = ImageReader.newInstance(1920, 1080, ImageFormat.YUV_420_888, 1) imageReader?.setOnImageAvailableListener( mOnImageAvailableListener, mBackgroundHandler )

private val mOnImageAvailableListener = OnImageAvailableListener { p0 ->

            val image = p0.acquireNextImage()

            /* get video data */
            if (yuvImage != null && recording) {
                (yuvImage!!.image[0].position(0) as ByteBuffer).put(image!!.planes[0].buffer)

                val bytes = bzyuvUtil?.preHandleYUV420(image, false, 0)
                val newBytes = ByteArray(1920 * 1080 * 3 / 2)
                BZYUVUtil.yuvI420ToNV21(bytes, newBytes, 1920, 1080)
                (yuvImage!!.image[0].position(0) as ByteBuffer).put(newBytes)

                try {
                    Log.v(
                        LOG_FFMPEG,
                        "Writing Frame Telephone"
                    )
                    val t = 1000 * (System.currentTimeMillis() - startTime)
                    if (t > ffMpegFrameRecorder?.getTimestamp()!!) {
                        ffMpegFrameRecorder?.setTimestamp(t)
                    }

                    ffMpegFrameRecorder?.record(yuvImage)
                    isRecordingVideo.set(true)
                } catch (e: FFmpegFrameRecorder.Exception) {
                    Log.v(
                        LOG_FFMPEG,
                        e.message!!
                    )
                    e.printStackTrace()
                }
            }

            image?.close()
        }
    }
}

build.gradle : task javacppExtract(type: Copy) { dependsOn configurations.javacpp

from { configurations.javacpp.collect { zipTree(it) } }
include "lib/**"
into "$buildDir/javacpp/"
android.sourceSets.main.jniLibs.srcDirs += ["$buildDir/javacpp/lib/"]

tasks.getByName('preBuild').dependsOn javacppExtract

} // api 'org.bytedeco:javacv-platform:1.5.10-SNAPSHOT' implementation group: 'org.bytedeco', name: 'javacv', version: "1.5.9" // javacpp group: 'org.bytedeco', name: 'openblas-platform', version: "5.1.2-1.5.8" javacpp group: 'org.bytedeco', name: 'opencv-platform', version: "4.7.0-1.5.9" javacpp group: 'org.bytedeco', name: 'ffmpeg-platform', version: "6.0-1.5.9"

implementation 'com.guaishou.bzlib:bzyuv:1.1.19@aar'

// api "org.bytedeco:javacv-platform:1.5.9"

Logs : I/SUPPORT_ENCODER_TELEPHONE: avCodec != null, h264_mediacodec/ H.264 Android MediaCodec encoder I/OMXClient: IOmx service obtained I/ExtendedACodec: setupVideoEncoder() W/OMXUtils: do not know color format 0x7fa30c04 = 2141391876 W/OMXUtils: do not know color format 0x7fa30c00 = 2141391872 W/OMXUtils: do not know color format 0x7f000789 = 2130708361 E/ACodec: [OMX.qcom.video.encoder.avc] does not support color format 19 E/ExtendedACodec: [OMX.qcom.video.encoder.avc] configureCodec returning error -61 E/ACodec: signalError(omxError 0x80001001, internalError -61) E/ACodec: [OMX.qcom.video.encoder.avc] configureCodec returning error -61 E/ACodec: signalError(omxError 0x80001001, internalError -61) E/MediaCodec: Codec reported err 0xffffffc3, actionCode 0, while in state 3 E/MediaCodec: Codec reported err 0xffffffc3, actionCode 0, while in state 0 E/MediaCodec: configure failed with err 0xffffffc3, resetting... I/OMXClient: IOmx service obtained W/System.err: org.bytedeco.javacv.FFmpegFrameRecorder$Exception: avcodec_open2() error -542398533: Could not open video codec. (For more details, make sure FFmpegLogCallback.set() has been called.) W/System.err: at org.bytedeco.javacv.FFmpegFrameRecorder.startUnsafe(FFmpegFrameRecorder.java:791) W/System.err: at org.bytedeco.javacv.FFmpegFrameRecorder.start(FFmpegFrameRecorder.java:437)

Any help will be appreciated

Contributor guide