MediaCodec.java 中有几个创建组件的API 可用:
1. JAVA 层
其实 createDecoderByType 和 createByCodecName 的实现是一样的,都是创建了 MediaCodec 对象,只是nameIsType 这个参数 值不一样:
/frameworks/base/media/java/android/media/MediaCodec.java
1977 /**
1978 * Instantiate the preferred decoder supporting input data of the given mime type.
2001 * @param type The mime type of the input data.
2005 */
2006 @NonNull
2007 public static MediaCodec createDecoderByType(@NonNull String type)
2008 throws IOException {
2009 return new MediaCodec(type, true /* nameIsType */, false /* encoder */);
2010 }
==================
2030 /**
2031 * If you know the exact name of the component you want to instantiate
2032 * use this method to instantiate it. Use with caution.
2033 * Likely to be used with information obtained from {@link android.media.MediaCodecList}
2038 */
2039 @NonNull
2040 public static MediaCodec createByCodecName(@NonNull String name)
2041 throws IOException {
2042 return new MediaCodec(name, false /* nameIsType */, false /* encoder */);
2043 }
MediaCodec 对象初始化主要就是 创建了 Looper/Handler 然后就是调用native_setup 继续往下去初始化;
/frameworks/base/media/java/android/media/MediaCodec.java
2071 private MediaCodec(@NonNull String name, boolean nameIsType, boolean encoder) {
2072 this(name, nameIsType, encoder, -1 /* pid */, -1 /* uid */);
2073 }
====================
2075 private MediaCodec(@NonNull String name, boolean nameIsType, boolean encoder, int pid,
2076 int uid) {
2077 Looper looper; //创建 Looper
2078 if ((looper = Looper.myLooper()) != null) {
2079 mEventHandler = new EventHandler(this, looper); //创建Handler
2080 } else if ((looper = Looper.getMainLooper()) != null) {
2081 mEventHandler = new EventHandler(this, looper);
2082 } else {
2083 mEventHandler = null;
2084 }
2085 mCallbackHandler = mEventHandler;
2086 mOnFirstTunnelFrameReadyHandler = mEventHandler;
2087 mOnFrameRenderedHandler = mEventHandler;
2088
2089 mBufferLock = new Object();
2090
2091 // save name used at creation
2092 mNameAtCreation = nameIsType ? null : name;
2093
2094 native_setup(name, nameIsType, encoder, pid, uid);
2095 }
2. JNI
native_setup 调用到了JNI ,再来看JNI 的实现
/frameworks/base/media/jni/android_media_MediaCodec.cpp
3787 { "native_setup", "(Ljava/lang/String;ZZII)V",
3788 (void *)android_media_MediaCodec_native_setup },
=====================
3449 static void android_media_MediaCodec_native_setup(
3450 JNIEnv *env, jobject thiz,
3451 jstring name, jboolean nameIsType, jboolean encoder, int pid, int uid) {
3463 sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder, pid, uid);
3464
3465 const status_t err = codec->initCheck();
... //一些异常判断
3495
3496 codec->registerSelf();
3497
3498 setMediaCodec(env, thiz, codec);
===================
214 JMediaCodec::JMediaCodec(
215 JNIEnv *env, jobject thiz,
216 const char *name, bool nameIsType, bool encoder, int pid, int uid)
217 : mClass(NULL),
218 mObject(NULL) {
224
225 mLooper = new ALooper;
226 mLooper->setName("MediaCodec_looper");
227
228 mLooper->start(
229 false, // runOnCallingThread
230 true, // canCallJava
231 ANDROID_PRIORITY_VIDEO);
232
233 if (nameIsType) {
234 mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus, pid, uid);
238 } else {
239 mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus, pid, uid);
240 mNameAtCreation = name;
241 }
242 CHECK((mCodec != NULL) != (mInitStatus != OK));
243 }
这边 JNI 根据 nameIsType 分了两个API CreateByType & CreateByComponentName
3. C++
JNI 往下就是调用到 MediaCodec.cpp 中的 CreateByType :看了下CreateByType 的实现:
- 首先 findMatchingCodecs 去寻找匹配的matchingCodecs,可能会找到多个;
- 然后根据找到的 matchingCodecs 循环去创建MediaCodec 知道创建成功就返回 Codec;
/frameworks/av/media/libstagefright/MediaCodec.cpp
911 sp<MediaCodec> MediaCodec::CreateByType(
912 const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid,
913 uid_t uid) {
914 sp<AMessage> format;
915 return CreateByType(looper, mime, encoder, err, pid, uid, format);
916 }
=================
918 sp<MediaCodec> MediaCodec::CreateByType(
919 const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid,
920 uid_t uid, sp<AMessage> format) {
921 Vector<AString> matchingCodecs;
922
923 MediaCodecList::findMatchingCodecs(
924 mime.c_str(),
925 encoder,
926 0,
927 format,
928 &matchingCodecs); //寻找匹配的 Codecs
929
930 if (err != NULL) {
931 *err = NAME_NOT_FOUND;
932 }
933 for (size_t i = 0; i < matchingCodecs.size(); ++i) {
934 sp<MediaCodec> codec = new MediaCodec(looper, pid, uid); //创建 MediaCodec
935 AString componentName = matchingCodecs[i];
936 status_t ret = codec->init(componentName); //初始化 component
937 if (err != NULL) {
938 *err = ret;
939 }
940 if (ret == OK) {
941 return codec;
942 }
943 ALOGD("Allocating component '%s' failed (%d), try next one.",
944 componentName.c_str(), ret);
945 }
946 return NULL;
947 }
Step1: findMatchingCodecs 的实现
/frameworks/av/media/libstagefright/MediaCodecList.cpp
349 void MediaCodecList::findMatchingCodecs(
350 const char *mime, bool encoder, uint32_t flags,
351 Vector<AString> *matches) {
352 sp<AMessage> format; // initializes as clear/null
353 findMatchingCodecs(mime, encoder, flags, format, matches);
354 }
findMatchingCodecs 主要是为了根据 mime 找到 匹配的Codec 用于解码
==> 准备单独开一篇来分析寻找匹配的Codecs 以及 Codecs 的中的支持的格式是如何加载的 《MediaCodec(五) findMatchingCodecs 的流程及组件加载》
Step2: 找到匹配的Codecs 后就会去 new MediaCodec
579 MediaCodec(
580 const sp<ALooper> &looper, pid_t pid, uid_t uid,
581 std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase = nullptr,
582 std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo = nullptr);
=========================
/frameworks/av/media/libstagefright/MediaCodec.cpp
1006 MediaCodec::MediaCodec(
1007 const sp<ALooper> &looper, pid_t pid, uid_t uid,
1008 std::function<sp<CodecBase>(const AString &, const char *)> getCodecBase,
1009 std::function<status_t(const AString &, sp<MediaCodecInfo> *)> getCodecInfo)
1010 : mState(UNINITIALIZED), // UNINITIALIZED
1012 mLooper(looper),
1013 mCodec(NULL),
1049 mGetCodecInfo(getCodecInfo) {
1050 mCodecId = GenerateCodecId();
1051 mResourceManagerProxy = new ResourceManagerServiceProxy(pid, uid,
1052 ::ndk::SharedRefBase::make<ResourceManagerClient>(this, pid, uid));
1053 if (!mGetCodecBase) {
1054 mGetCodecBase = [](const AString &name, const char *owner) {
1055 return GetCodecBase(name, owner);
1056 };
1057 }
1058 if (!mGetCodecInfo) {
1059 mGetCodecInfo = [&log = mErrorLog](const AString &name,
1060 sp<MediaCodecInfo> *info) -> status_t {
1061 *info = nullptr;
1062 const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
1067 AString tmp = name;
1068 if (tmp.endsWith(".secure")) {
1069 tmp.erase(tmp.size() - 7, 7);
1070 }
1071 for (const AString &codecName : { name, tmp }) {
1072 ssize_t codecIdx = mcl->findCodecByName(codecName.c_str());
1076 *info = mcl->getCodecInfo(codecIdx);
1077 return OK;
1078 }
1079 log.log(LOG_TAG, base::StringPrintf("Codec with name '%s' is not found on the device.",
1080 name.c_str()));
1081 return NAME_NOT_FOUND;
1082 };
1083 }
1084
1085 // we want an empty metrics record for any early getMetrics() call
1086 // this should be the *only* initMediametrics() call that's not on the Looper thread
1087 initMediametrics();
(1) GenerateCodecId 看起来为 Codec 生成一个 随机的 ID (用于判别Codec)
989 // GenerateCodecId generates a 64bit Random ID for each codec that is created.
990 // The Codec ID is generated as:
991 // - A process-unique random high 32bits
992 // - An atomic sequence low 32bits
993 //
994 static uint64_t GenerateCodecId() {
995 static std::atomic_uint64_t sId = [] {
996 std::random_device rd;
997 std::mt19937 gen(rd());
998 std::uniform_int_distribution<uint32_t> distrib(0, UINT32_MAX);
999 uint32_t randomID = distrib(gen);
1000 uint64_t id = randomID;
1001 return id << 32;
1002 }();
1003 return sId++;
1004 }
(2)mGetCodecInfo = 这步主要是给 mGetCodecInfo 赋值函数实现 目前还不会运行;
简单看下主要是为了在 MediaCodecList 中 findCodecByName(codecName.c_str()); 找到设备中匹配的 Codec 获取 CodecInfo
/frameworks/av/media/libstagefright/MediaCodec.cpp
294 ssize_t MediaCodecList::findCodecByName(const char *name) const {
295 Vector<AString> aliases;
296 for (size_t i = 0; i < mCodecInfos.size(); ++i) {
297 if (strcmp(mCodecInfos[i]->getCodecName(), name) == 0) { //比较Codec名字
298 return i;
299 }
300 mCodecInfos[i]->getAliases(&aliases); //比较别名
301 for (const AString &alias : aliases) {
302 if (alias == name) {
303 return i;
304 }
305 }
306 }
307
308 return -ENOENT;
309 }
===================
3216 status_t MediaCodec::getCodecInfo(sp<MediaCodecInfo> *codecInfo) const {
3217 sp<AMessage> msg = new AMessage(kWhatGetCodecInfo, this);
3218
3219 sp<AMessage> response;
3220 status_t err;
3221 if ((err = PostAndAwaitResponse(msg, &response)) != OK) { //Aloop 发送消息
3222 return err;
3223 }
3224
3225 sp<RefBase> obj;
3226 CHECK(response->findObject("codecInfo", &obj));
3227 *codecInfo = static_cast<MediaCodecInfo *>(obj.get());
3228
3229 return OK;
3230 }
--------------
5294 case kWhatGetCodecInfo:
5295 {
5296 sp<AReplyToken> replyID;
5297 CHECK(msg->senderAwaitsResponse(&replyID));
5298
5299 sp<AMessage> response = new AMessage;
5300 response->setObject("codecInfo", mCodecInfo);
//获取到的结果就是 mCodecInfo,而 mCodecInfo 是在 MediaCodec::init 中初始化的
5301 response->postReply(replyID);
5302 break;
5303 }
(3)initMediametrics “初始化媒体指标”:看起来是在初始化一些变量
1105 // except for in constructor, called from the looper thread (and therefore mutexed)
1106 void MediaCodec::initMediametrics() {
1107 if (mMetricsHandle == 0) {
1108 mMetricsHandle = mediametrics_create(kCodecKeyName);
1109 }
1110
1111 mLatencyHist.setup(kLatencyHistBuckets, kLatencyHistWidth, kLatencyHistFloor);
1112
1113 {
1114 Mutex::Autolock al(mRecentLock);
1115 for (int i = 0; i<kRecentLatencyFrames; i++) {
1116 mRecentSamples[i] = kRecentSampleInvalid;
1117 }
1118 mRecentHead = 0;
1119 }
1120
1121 {
1122 Mutex::Autolock al(mLatencyLock);
1123 mBuffersInFlight.clear();
1124 mNumLowLatencyEnables = 0;
1125 mNumLowLatencyDisables = 0;
1126 mIsLowLatencyModeOn = false;
1127 mIndexOfFirstFrameWhenLowLatencyOn = -1;
1128 mInputBufferCounter = 0;
1129 }
1130
1131 mLifetimeStartNs = systemTime(SYSTEM_TIME_MONOTONIC);
1132 resetMetricsFields();
1133 }
到这边 new MediaCodec 就看完了,主要作用就是初始化一些变量和函数,同时根据name 获取到设备支持的Codec
Step 3:codec->init(componentName); 这一步内容非常多也很重要,在第二篇里去看《MediaCodec(六) 从MediaCodec 到 Codec2 之 createCompetent(2)》