master ohmu/fastfetch-openbsd / src / detection / codec / codec_android.c
ohmu  ·  2026-10-15
  1#include "codec.h"
  2
  3#include "common/android/api.h"
  4#include "common/debug.h"
  5#include "common/strutil.h"
  6#include <media/NdkMediaCodec.h>
  7
  8static const struct {
  9    const char* mime;
 10    FFCodecType type;
 11} FF_CODEC_MIME_TO_TYPE[] = {
 12    { "video/3gpp", FF_CODEC_TYPE_H263 },
 13    { "video/h263", FF_CODEC_TYPE_H263 },
 14    { "video/mjpeg", FF_CODEC_TYPE_MJPEG },
 15    { "video/mpeg2", FF_CODEC_TYPE_MPEG2 },
 16    { "video/mp2v-es", FF_CODEC_TYPE_MPEG2 },
 17    { "video/mp4v-es", FF_CODEC_TYPE_DIVX_XVID },
 18    { "video/avc", FF_CODEC_TYPE_H264 },
 19    { "video/hevc", FF_CODEC_TYPE_HEVC },
 20    { "video/x-vnd.on2.vp8", FF_CODEC_TYPE_VP8 },
 21    { "video/x-vnd.on2.vp9", FF_CODEC_TYPE_VP9 },
 22    { "video/av01", FF_CODEC_TYPE_AV1 },
 23    { "video/vvc", FF_CODEC_TYPE_VVC },
 24};
 25
 26static bool ffCodecIsLikelySoftware(const char* codecName) {
 27    if (!codecName) {
 28        return true;
 29    }
 30
 31    return ffStrStartsWith(codecName, "OMX.google.") ||
 32        ffStrStartsWith(codecName, "c2.android.") ||
 33        ffStrStartsWith(codecName, "OMX.ffmpeg.") ||
 34        ffStrStartsWith(codecName, "OMX.PV.");
 35}
 36
 37// Only the name query is newer than the API level this build targets: AMediaCodec_getName and
 38// AMediaCodec_releaseName are API 28, while creating and deleting a codec is API 21.
 39FF_ANDROID_REQUIRES_API(28) static bool ffCodecIsHardwareAccelerated(AMediaCodec* codec) {
 40    if (!codec) {
 41        return false;
 42    }
 43
 44    char* codecName = nullptr;
 45    media_status_t status = AMediaCodec_getName(codec, &codecName);
 46    if (status != AMEDIA_OK || !codecName) {
 47        return false;
 48    }
 49
 50    bool isHardware = !ffCodecIsLikelySoftware(codecName);
 51    AMediaCodec_releaseName(codec, codecName);
 52    return isHardware;
 53}
 54
 55FF_ANDROID_REQUIRES_API(28) static const char* ffDetectCodecNativeImpl(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/) {
 56    FFCodecType decoders = FF_CODEC_TYPE_NONE;
 57    FFCodecType encoders = FF_CODEC_TYPE_NONE;
 58
 59    for (uint32_t i = 0; i < ARRAY_SIZE(FF_CODEC_MIME_TO_TYPE); ++i) {
 60        const char* mime = FF_CODEC_MIME_TO_TYPE[i].mime;
 61        FFCodecType type = FF_CODEC_MIME_TO_TYPE[i].type;
 62
 63        if ((options->showType & FF_CODEC_SHOW_TYPE_DECODER) && !(decoders & type)) {
 64            AMediaCodec* decoder = AMediaCodec_createDecoderByType(mime);
 65            if (decoder) {
 66                if (ffCodecIsHardwareAccelerated(decoder)) {
 67                    decoders |= type;
 68                }
 69                AMediaCodec_delete(decoder);
 70            }
 71        }
 72
 73        if ((options->showType & FF_CODEC_SHOW_TYPE_ENCODER) && !(encoders & type)) {
 74            AMediaCodec* encoder = AMediaCodec_createEncoderByType(mime);
 75            if (encoder) {
 76                if (ffCodecIsHardwareAccelerated(encoder)) {
 77                    encoders |= type;
 78                }
 79                AMediaCodec_delete(encoder);
 80            }
 81        }
 82    }
 83
 84    if (decoders != FF_CODEC_TYPE_NONE || encoders != FF_CODEC_TYPE_NONE) {
 85        FFCodecResult* item = FF_LIST_ADD(FFCodecResult, *result);
 86        ffStrbufInitStatic(&item->gpu, "Default");
 87        item->decoders = decoders;
 88        item->encoders = encoders;
 89        item->platformApi = "AMediaCodec";
 90    }
 91
 92    return nullptr;
 93}
 94
 95const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/) {
 96    if (FF_ANDROID_API_AT_LEAST(28)) {
 97        return ffDetectCodecNativeImpl(options, result);
 98    }
 99
100    // Reading the codec name is the only way to tell a hardware codec from a software one. Without
101    // it there is nothing to report, and listing the codecs as if they were accelerated would be a
102    // guess, so say why instead.
103    FF_DEBUG("AMediaCodec_getName() requires Android 9 (API 28)");
104    return "AMediaCodec_getName() requires Android 9 (API 28)";
105}