summaryrefslogtreecommitdiffstats
path: root/src/detection/codec/codec_android.c
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/codec/codec_android.c
Add the files
Diffstat (limited to 'src/detection/codec/codec_android.c')
-rw-r--r--src/detection/codec/codec_android.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/detection/codec/codec_android.c b/src/detection/codec/codec_android.c
new file mode 100644
index 0000000..238dab7
--- /dev/null
+++ b/src/detection/codec/codec_android.c
@@ -0,0 +1,102 @@
+#include "codec.h"
+
+#include "common/library.h"
+#include "common/strutil.h"
+#undef __INTRODUCED_IN
+#define __INTRODUCED_IN(...)
+#include <media/NdkMediaCodec.h>
+
+static const struct {
+ const char* mime;
+ FFCodecType type;
+} FF_CODEC_MIME_TO_TYPE[] = {
+ { "video/3gpp", FF_CODEC_TYPE_H263 },
+ { "video/h263", FF_CODEC_TYPE_H263 },
+ { "video/mjpeg", FF_CODEC_TYPE_MJPEG },
+ { "video/mpeg2", FF_CODEC_TYPE_MPEG2 },
+ { "video/mp2v-es", FF_CODEC_TYPE_MPEG2 },
+ { "video/mp4v-es", FF_CODEC_TYPE_DIVX_XVID },
+ { "video/avc", FF_CODEC_TYPE_H264 },
+ { "video/hevc", FF_CODEC_TYPE_HEVC },
+ { "video/x-vnd.on2.vp8", FF_CODEC_TYPE_VP8 },
+ { "video/x-vnd.on2.vp9", FF_CODEC_TYPE_VP9 },
+ { "video/av01", FF_CODEC_TYPE_AV1 },
+ { "video/vvc", FF_CODEC_TYPE_VVC },
+};
+
+static bool ffCodecIsLikelySoftware(const char* codecName) {
+ if (!codecName) {
+ return true;
+ }
+
+ return ffStrStartsWith(codecName, "OMX.google.") ||
+ ffStrStartsWith(codecName, "c2.android.") ||
+ ffStrStartsWith(codecName, "OMX.ffmpeg.") ||
+ ffStrStartsWith(codecName, "OMX.PV.");
+}
+
+static bool ffCodecIsHardwareAccelerated(
+ AMediaCodec* codec,
+ __typeof__(&AMediaCodec_getName) ffAMediaCodec_getName,
+ __typeof__(&AMediaCodec_releaseName) ffAMediaCodec_releaseName) {
+ if (!codec) {
+ return false;
+ }
+
+ char* codecName = NULL;
+ media_status_t status = ffAMediaCodec_getName(codec, &codecName);
+ if (status != AMEDIA_OK || !codecName) {
+ return false;
+ }
+
+ bool isHardware = !ffCodecIsLikelySoftware(codecName);
+ ffAMediaCodec_releaseName(codec, codecName);
+ return isHardware;
+}
+
+const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/) {
+ FF_LIBRARY_LOAD_MESSAGE(mediandk, "libmediandk.so", 0)
+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mediandk, AMediaCodec_createDecoderByType)
+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mediandk, AMediaCodec_createEncoderByType)
+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mediandk, AMediaCodec_delete)
+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mediandk, AMediaCodec_getName)
+ FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mediandk, AMediaCodec_releaseName)
+
+ FFCodecType decoders = FF_CODEC_TYPE_NONE;
+ FFCodecType encoders = FF_CODEC_TYPE_NONE;
+
+ for (uint32_t i = 0; i < ARRAY_SIZE(FF_CODEC_MIME_TO_TYPE); ++i) {
+ const char* mime = FF_CODEC_MIME_TO_TYPE[i].mime;
+ FFCodecType type = FF_CODEC_MIME_TO_TYPE[i].type;
+
+ if ((options->showType & FF_CODEC_SHOW_TYPE_DECODER) && !(decoders & type)) {
+ AMediaCodec* decoder = ffAMediaCodec_createDecoderByType(mime);
+ if (decoder) {
+ if (ffCodecIsHardwareAccelerated(decoder, ffAMediaCodec_getName, ffAMediaCodec_releaseName)) {
+ decoders |= type;
+ }
+ ffAMediaCodec_delete(decoder);
+ }
+ }
+
+ if ((options->showType & FF_CODEC_SHOW_TYPE_ENCODER) && !(encoders & type)) {
+ AMediaCodec* encoder = ffAMediaCodec_createEncoderByType(mime);
+ if (encoder) {
+ if (ffCodecIsHardwareAccelerated(encoder, ffAMediaCodec_getName, ffAMediaCodec_releaseName)) {
+ encoders |= type;
+ }
+ ffAMediaCodec_delete(encoder);
+ }
+ }
+ }
+
+ if (decoders != FF_CODEC_TYPE_NONE || encoders != FF_CODEC_TYPE_NONE) {
+ FFCodecResult* item = FF_LIST_ADD(FFCodecResult, *result);
+ ffStrbufInitStatic(&item->gpu, "Default");
+ item->decoders = decoders;
+ item->encoders = encoders;
+ item->platformApi = "AMediaCodec";
+ }
+
+ return NULL;
+}