1 内容
文件路径:
code:android/device/qcom/msm8996(平台名)或者android/frameworks/av/media/libstagefright/data
设备:/vendor/etc/media_codecs.xml
<MediaCodec name="OMX.google.amrnb.encoder" type="audio/3gpp">
<Limit name="channel-count" max="1" />
<Limit name="sample-rate" ranges="8000" />
<Limit name="bitrate" range="4750-12200" />
<Feature name="bitrate-modes" value="CBR" />
</MediaCodec>
定义当前设备所支持的编码器配置。
还有另一款"c2.android.amrnb.encoder"
2 加载及使用
2.1 文件加载log
2.2 解析文件
关于mediacodec.xml文件的解析,查看log可以发现有多处。
首先,存放media_codec.xml的文件夹有多个,所以会先查找对应的文件夹
然后,获取到了文件路径,对xml文件进行解析
重点是MediaCodecsXmlParser::parseXmlPath函数进行处理的。
最终调用到MediaCodecsXmlParser::Impl::Parser::parseXmlFile函数中,打开并遍历xml文件的节点,将xml文件中的数据存入parser中。
//处理xml文件
status_t MediaCodecsXmlParser::Impl::parseXmlPath(const std::string &path) {
std::lock_guard<std::mutex> guard(mLock);
//1. 获取路径
std::string vendorPath = getVendorXmlPath(path);
// save state (even though we should always be at toplevel here)
State::RestorePoint rp = mState.createRestorePoint();
Parser parser(&mState, vendorPath);
//2. 解析xml文件
parser.parseXmlFile();
mState.restore(rp);
if (parser.getStatus() != OK) {
ALOGD("parseXmlPath(%s) failed with %s", vendorPath.c_str(), asString(parser.getStatus()));
}
mParsingStatus = combineStatus(mParsingStatus, parser.getStatus());
return parser.getStatus();
}
//获取文件路径
std::string getVendorXmlPath(const std::string &path) {
std::string vendorPath;
std::string result = path;
if (!strncmp(path.c_str(), "/vendor/etc/media_codecs.xml",
strlen("/vendor/etc/media_codecs.xml"))) {
vendorPath = "/vendor/etc/media_codecs_vendor";
} else if (!strncmp(path.c_str(), "/vendor/etc/media_codecs_performance.xml",
strlen("/vendor/etc/media_codecs_performance.xml"))) {
vendorPath = "/vendor/etc/media_codecs_performance";
}
}
//解析xml文件
void MediaCodecsXmlParser::Impl::Parser::parseXmlFile() {
const char *path = mPath.c_str();
ALOGD("parsing %s...", path);
FILE *file = fopen(path, "r");
mParser = std::shared_ptr<XML_ParserStruct>(
::XML_ParserCreate(nullptr),
[](XML_ParserStruct *parser) { ::XML_ParserFree(parser); });
LOG_FATAL_IF(!mParser, "XML_MediaCodecsXmlParserCreate() failed.");
::XML_SetUserData(mParser.get(), this);
::XML_SetElementHandler(mParser.get(), StartElementHandlerWrapper, EndElementHandlerWrapper);
static constexpr int BUFF_SIZE = 512;
while (mStatus == OK) {
void *buff = ::XML_GetBuffer(mParser.get(), BUFF_SIZE);
int bytes_read = ::fread(buff, 1, BUFF_SIZE, file);
XML_Status status = ::XML_ParseBuffer(mParser.get(), bytes_read, bytes_read == 0);
}
mParser.reset();
fclose(file);
}
根据代码查看,发现是OmxStore::OmxStore调用的。
OmxStore::OmxStore(){
MediaCodecsXmlParser parser;
parser.parseXmlFilesInSearchDirs(xmlNames, searchDirs);
if (profilingResultsXmlPath != nullptr) {
parser.parseXmlPath(profilingResultsXmlPath);
}
mParsingStatus = toStatus(parser.getParsingStatus());
}
怀疑:
mediacodec创建的时候会执行MediaCodecList::getInstance,目前怀疑MediaCodecList应该会和omxstore有关联,代码后续继续追。
status_t MediaCodec::init(const AString &name, bool nameIsType) {
const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
for (const AString &codecName : { name, tmp }) {
ssize_t codecIdx = mcl->findCodecByName(codecName.c_str());
mCodecInfo = mcl->getCodecInfo(codecIdx);
}
}
sp<IMediaCodecList> MediaCodecList::getInstance() {
sRemoteList = getLocalInstance();
}
sp<IMediaCodecList> MediaCodecList::getLocalInstance() {
MediaCodecList *codecList = new MediaCodecList(GetBuilders());
}
2.3 使用
先看下使用。
经过了mediaprofile的筛选,根据app传下来codec类型,匹配得到两个encoder,最终录制选择OMX.google.amrnb.encoder,选择哪个encoder应该是有一个打分机制,后续再追。
3 小结
目前只追到了OmxStore初始化的时候加载media_codec.xml文件,并存放到MediaCodecsXmlParser parser中。
根据log来看,实际使用的时候是再mediacodeclist中寻找匹配的encoder,所以怀疑最终omxstore会和mediacodeclist相关联,这个后续再追。