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}