termux / termux-packages

A package build system for Termux.
https://termux.dev
Other
13.33k stars 3.07k forks source link

[Bug]: ffmpeg failure without specifying the video codec #19396

Closed c1400700226 closed 8 months ago

c1400700226 commented 8 months ago

Problem description

ffmpeg failure without specifying the video codec

[amediacodec_ndk @ 0xb400007342d7d540] Encoder configure failed, -10000 [h264_mediacodec @ 0xb400007342d8a800] MediaCodec configure failed, Generic error in an external library [vost#0:0/h264_mediacodec @ 0xb400007342d84780] Error while opening encoder - maybe incorrect parameters such as bit_rate, rate, width or height. Error while filtering: Generic error in an external library [out#0/mp4 @ 0xb400007342d09780] Nothing was written into output file, because at least one of its streams received no packets.

No problem if you specify the video codec for example "-c:v libx264"

What steps will reproduce the bug?

ffmpeg -i test.mp4 output.mp4

What is the expected behavior?

No response

System information

termux-info: Version 0.118 Termux Variables: TERMUX_APK_RELEASE=UNKNOWN TERMUX_APP_PACKAGE_MANAGER=apt TERMUX_APP_PID=13495 TERMUX_IS_DEBUGGABLE_BUILD=0 TERMUX_MAIN_PACKAGE_FORMAT=debian TERMUX_VERSION=0.118.0 TERMUX__USER_ID=0 Packages CPU architecture: aarch64 Subscribed repositories:

sources.list

deb https://packages-cf.termux.dev/apt/termux-main stable main

root-repo (sources.list.d/root.list)

deb https://packages-cf.termux.dev/apt/termux-root/ root stable Updatable packages: command-not-found/stable 2.4.0-14 aarch64 [upgradable from: 2.4.0-13] debianutils/stable 5.17 aarch64 [upgradable from: 5.16] libxcb/stable 1.16.1 aarch64 [upgradable from: 1.16] termux-tools/stable 1.40.7 all [upgradable from: 1.40.6] termux-tools version: 1.40.6 Android version: 11 Kernel build information: Linux localhost 4.19.113-perf-g2dec83098f88 #1 SMP PREEMPT Fri Dec 17 11:18:47 CST 2021 aarch64 Android Device manufacturer: Xiaomi Device model: M2012K11AC LD Variables: LD_LIBRARY_PATH= LD_PRELOAD=/data/data/com.termux/files/usr/lib/libtermux-exec.so

HusniMuhammad commented 8 months ago

I think it's a correct behavior

Biswa96 commented 8 months ago

I think it's a correct behavior

I do not think so. This issue seems to be a duplicate of #18023 and can be fixed after reverting this 097206d50d34ab7fc0eb4c0ff20ae80ee73fd901 commit @truboxl

Biswa96 commented 8 months ago

I got the hint from this thread https://android.stackexchange.com/questions/253750/hardware-accelerated-ffmpeg-using-mediacodec-on-android

HusniMuhammad commented 8 months ago

I got the hint from this thread https://android.stackexchange.com/questions/253750/hardware-accelerated-ffmpeg-using-mediacodec-on-android

Ok now got it, but ffmpeg in termux not hardware accelerated though particularly arm32.

sylirre commented 8 months ago

Mediacodec actually works in Termux. Nothing is broken.

Screenshot_20240303-115856_Termux


In my case I had only to disable audio stream (-an option) because it triggered an error in aac encoder (unsupported channel layouts). But video recoding works perfectly using mediacodec.

In your case the issue may be a video with properties not supported by mediacodec natively. You may need to specify additional options. Otherwise indeed switch to libx264.

sylirre commented 8 months ago

Another attempt, 8k h264 + aac. Using default ffmpeg configuration. Zero issues.

Screenshot_20240303-121349_Termux_1

P.S. In case with 8k, the mediacodec is a must have feature for ffmpeg. I would be against reverting commit as suggested before. Because with libx264 it takes much more time and overloads the device.

c1400700226 commented 8 months ago

Another attempt, 8k h264 + aac. Using default ffmpeg configuration. Zero issues.

Screenshot_20240303-121349_Termux_1

P.S. In case with 8k, the mediacodec is a must have feature for ffmpeg. I would be against reverting commit as suggested before. Because with libx264 it takes much more time and overloads the device.

Weird, I did reinstall termux, problem still

sylirre commented 8 months ago

Problem can happen due to unsupported properties of your original video file or some incompatibility between ffmpeg and mediacodec implementation on your device.

I will try it on other my devices, maybe one of them will show behavior similar to yours.

Edit: still can't reproduce the issue on all of my devices (all AArch64, Android OS 8/14). Tried h264 video from various sources (camera, YouTube).

truboxl commented 8 months ago

Weird, I did reinstall termux, problem still

You are not helping if you are not posting the full termux info

Biswa96 commented 8 months ago

I have attached two text file with the output of termux-info and ffmpeg error message.

ffmpeg-output.txt termux-info.txt

c1400700226 commented 8 months ago

Problem can happen due to unsupported properties of your original video file or some incompatibility between ffmpeg and mediacodec implementation on your device.

I will try it on other my devices, maybe one of them will show behavior similar to yours.

Edit: still can't reproduce the issue on all of my devices (all AArch64, Android OS 8/14). Tried h264 video from various sources (camera, YouTube).

It happens with any video. And I have tried static compiled ffmpeg, no such problem.

c1400700226 commented 8 months ago

I have attached two text file with the output of termux-info and ffmpeg error message.

ffmpeg-output.txt termux-info.txt

Exactly the same situation here

c1400700226 commented 8 months ago

Weird, I did reinstall termux, problem still

You are not helping if you are not posting the full termux info

Sorry, I have updated the post

truboxl commented 8 months ago

Referring https://github.com/termux/termux-packages/issues/18023#issuecomment-1897987187

Does adding -pix_fmt nv12 helped?

Biswa96 commented 8 months ago

I have ran the following command. It shows some warnings/errors in the output but the ffmpeg process continues without exiting.

ffmpeg -hwaccel mediacodec -i test.mp4 -c:a copy -c:v h264_mediacodec -b:v 2M -pix_fmt nv12 output.mp4

I have attached the output in a text file here. ffmpeg-output-pix-fmt-nv12.txt

c1400700226 commented 8 months ago

Referring #18023 (comment)

Does adding -pix_fmt nv12 helped?

Yes, it works with this parameter. Or just add "-c:v libx264". But both shouldn't be necessary.

truboxl commented 8 months ago

-c:v libx264 is using CPU which will be super slow.

The bug is ffmpeg mediacodec limited detection mechanism as noted by the ffmpeg developer who provided the workaround. If by reverting means turn off mediacodec support, you will be left with CPU encoding. I rather fix the bug than to turn off support. I will see how to switch to NV12 by default/fallback if that is possible.

Biswa96 commented 8 months ago

Is there any way to detect if the underlying hardware is capable of the ffmpeg mediacodec, like lscpu, vulkaninfo tools?

Also, is the issue related to any software like binary blobs? I am running LineageOS 21.

truboxl commented 8 months ago

Mediacodec via NDK is still new for ffmpeg. So I expect @quink-black to answer questions and not some random stackexchange or reddit user.

quink-black commented 8 months ago

Referring #18023 (comment) Does adding -pix_fmt nv12 helped?

Yes, it works with this parameter. Or just add "-c:v libx264". But both shouldn't be necessary.

  1. It's very important to specify the encoder. Hardware encoder can be significant faster than software encoder, and use less CPU/battery. Software encoder on mobile devices should only be applied on low resolution cases.

  2. Whether -pix_fmt nv12 is needed depends on the device. It's well known some Qualcomm chips don't support yuv420p as encoder input format, but other deivces have no such problem. What's the real problem is that, Android NDK don't provide API to query what format is supported. There is an ugly Java API, it's not useful here since we have no access to JVM.

So, due to the missing API and it's device dependent, I don't have a idea to solve it automatically. There is an easy method: always use -pix_fmt nv12 since it should work on almost all devices.

I will add a hint message to FFmpeg.

diff --git a/libavcodec/mediacodecenc.c b/libavcodec/mediacodecenc.c
index 086b545590..984014f1b1 100644
--- a/libavcodec/mediacodecenc.c
+++ b/libavcodec/mediacodecenc.c
@@ -319,6 +319,9 @@  static av_cold int mediacodec_init(AVCodecContext *avctx)
     ret = ff_AMediaCodec_configure(s->codec, format, s->window, NULL, ret);
     if (ret) {
         av_log(avctx, AV_LOG_ERROR, "MediaCodec configure failed, %s\n", av_err2str(ret));
+        if (avctx->pix_fmt == AV_PIX_FMT_YUV420P)
+            av_log(avctx, AV_LOG_ERROR, "Please try -pix_fmt nv12, some devices don't "
+                                        "support yuv420p as encoder input format.\n");
         goto bailout;
     }
c1400700226 commented 8 months ago

Referring #18023 (comment) Does adding -pix_fmt nv12 helped?

Yes, it works with this parameter. Or just add "-c:v libx264". But both shouldn't be necessary.

  1. It's very important to specify the encoder. Hardware encoder can be significant faster than software encoder, and use less CPU/battery. Software encoder on mobile devices should only be applied on low resolution cases.
  2. Whether -pix_fmt nv12 is needed depends on the device. It's well known some Qualcomm chips don't support yuv420p as encoder input format, but other deivces have no such problem. What's the real problem is that, Android NDK don't provide API to query what format is supported. There is an ugly Java API, it's not useful here since we have no access to JVM.

So, due to the missing API and it's device dependent, I don't have a idea to solve it automatically. There is an easy method: always use -pix_fmt nv12 since it should work on almost all devices.

I will add a hint message to FFmpeg.

diff --git a/libavcodec/mediacodecenc.c b/libavcodec/mediacodecenc.c
index 086b545590..984014f1b1 100644
--- a/libavcodec/mediacodecenc.c
+++ b/libavcodec/mediacodecenc.c
@@ -319,6 +319,9 @@  static av_cold int mediacodec_init(AVCodecContext *avctx)
     ret = ff_AMediaCodec_configure(s->codec, format, s->window, NULL, ret);
     if (ret) {
         av_log(avctx, AV_LOG_ERROR, "MediaCodec configure failed, %s\n", av_err2str(ret));
+        if (avctx->pix_fmt == AV_PIX_FMT_YUV420P)
+            av_log(avctx, AV_LOG_ERROR, "Please try -pix_fmt nv12, some devices don't "
+                                        "support yuv420p as encoder input format.\n");
         goto bailout;
     }

Thanks for the info, but I think for compatibility reason software encoding should always be used by default, just like on other platforms.

quink-black commented 8 months ago

Referring #18023 (comment) Does adding -pix_fmt nv12 helped?

Yes, it works with this parameter. Or just add "-c:v libx264". But both shouldn't be necessary.

  1. It's very important to specify the encoder. Hardware encoder can be significant faster than software encoder, and use less CPU/battery. Software encoder on mobile devices should only be applied on low resolution cases.
  2. Whether -pix_fmt nv12 is needed depends on the device. It's well known some Qualcomm chips don't support yuv420p as encoder input format, but other deivces have no such problem. What's the real problem is that, Android NDK don't provide API to query what format is supported. There is an ugly Java API, it's not useful here since we have no access to JVM.

So, due to the missing API and it's device dependent, I don't have a idea to solve it automatically. There is an easy method: always use -pix_fmt nv12 since it should work on almost all devices. I will add a hint message to FFmpeg.

diff --git a/libavcodec/mediacodecenc.c b/libavcodec/mediacodecenc.c
index 086b545590..984014f1b1 100644
--- a/libavcodec/mediacodecenc.c
+++ b/libavcodec/mediacodecenc.c
@@ -319,6 +319,9 @@  static av_cold int mediacodec_init(AVCodecContext *avctx)
     ret = ff_AMediaCodec_configure(s->codec, format, s->window, NULL, ret);
     if (ret) {
         av_log(avctx, AV_LOG_ERROR, "MediaCodec configure failed, %s\n", av_err2str(ret));
+        if (avctx->pix_fmt == AV_PIX_FMT_YUV420P)
+            av_log(avctx, AV_LOG_ERROR, "Please try -pix_fmt nv12, some devices don't "
+                                        "support yuv420p as encoder input format.\n");
         goto bailout;
     }

Thanks for the info, but I think for compatibility reason software encoding should always be used by default, just like on other platforms.

FFmpeg doesn't sort encoders that way.

truboxl commented 8 months ago

Can help test https://github.com/termux/termux-packages/pull/19408 if it does changed to use libx264 by default?

Biswa96 commented 8 months ago

I have tested the CI artifact and it does change to libx264 by default now.