junit.framework.AssertionFailedError: Failed to get achievable frame rates for O

之前对于CTS测试的失败case接触不多,组长突然转了这样一个bug给我。
1027 I TestRunner: failed: testAvcGoog0Perf0320x0240(android.media.cts.VideoDecoderPerfTest)
05-23 01:24:17.675 1007 1027 I TestRunner: ----- begin exception -----
05-23 01:24:17.676 1007 1027 I TestRunner: junit.framework.AssertionFailedError: Failed to get achievable frame rates for OMX.google.h264.decoder video/avc 320x240
05-23 01:24:17.676 1007 1027 I TestRunner: at junit.framework.Assert.fail(Assert.java:50)
05-23 01:24:17.676 1007 1027 I TestRunner: at junit.framework.Assert.assertTrue(Assert.java:20)
05-23 01:24:17.676 1007 1027 I TestRunner: at junit.framework.Assert.assertNull(Assert.java:237)
05-23 01:24:17.676 1007 1027 I TestRunner: at android.media.cts.VideoDecoderPerfTest.decode(VideoDecoderPerfTest.java:107)
05-23 01:24:17.676 1007 1027 I TestRunner: at android.media.cts.VideoDecoderPerfTest.perf(VideoDecoderPerfTest.java:317)
05-23 01:24:17.676 1007 1027 I TestRunner: at android.media.cts.VideoDecoderPerfTest.testAvcGoog0Perf0320x0240(VideoDecoderPerfTest.java:335)
05-23 01:24:17.676 1007 1027 I TestRunner: at java.lang.reflect.Method.invoke(Native Method)
05-23 01:24:17.676 1007 1027 I TestRunner: at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:220)
05-23 01:24:17.676 1007 1027 I TestRunner: at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:205)
05-23 01:24:17.676 1007 1027 I TestRunner: at android.test.ActivityInstrumentationTestCase2.runTest(ActivityInstrumentationTestCase2.java:192)
05-23 01:24:17.676 1007 1027 I TestRunner: at junit.framework.TestCase.runBare(TestCase.java:134)
05-23 01:24:17.676 1007 1027 I TestRunner: at junit.framework.TestResult$1.protect(TestResult.java:115)
05-23 01:24:17.676 1007 1027 I TestRunner: at android.support.test.internal.runner.junit3.AndroidTestResult.runProtected(AndroidTestResult.java:77)
05-23 01:24:17.676 1007 1027 I TestRunner: at junit.framework.TestResult.run(TestResult.java:118)
05-23 01:24:17.676 1007 1027 I TestRunner: at android.support.test.internal.runner.junit3.AndroidTestResult.run(AndroidTestResult.java:55)
05-23 01:24:17.676 1007 1027 I TestRunner: at junit.framework.TestCase.run(TestCase.java:124)
05-23 01:24:17.676 1007 1027 I TestRunner: at android.support.test.internal.runner.junit3.NonLeakyTestSuite$NonLeakyTest.run(NonLeakyTestSuite.java:63)
05-23 01:24:17.676 1007 1027 I TestRunner: at android.support.test.internal.runner.junit3.AndroidTestSuite$2.run(AndroidTestSuite.java:111)
05-23 01:24:17.676 1007 1027 I TestRunner: at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
05-23 01:24:17.676 1007 1027 I TestRunner: at java.util.concurrent.FutureTask.run(FutureTask.java:266)
05-23 01:24:17.676 1007 1027 I TestRunner: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
05-23 01:24:17.676 1007 1027 I TestRunner: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
05-23 01:24:17.676 1007 1027 I TestRunner: at java.lang.Thread.run(Thread.java:764)
05-23 01:24:17.676 1007 1027 I TestRunner: ----- end exception -----
05-23 01:24:17.679 1007 1027 I TestRunner: finished: testAvcGoog0Perf0320x0240(android.media.cts.VideoDecoderPerfTest)
05-23 01:24:17.693 1007 1007 I MonitoringInstr: Activities that are still in CREATED to STOPPED: 1

我根据相关信息找了对应的测试case
http://androidxref.com/8.0.0_r4/xref/cts/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java

log失败的地方:
[url]http://androidxref.com/8.0.0_r4/xref/cts/common/device-side/util/src/com/android/compatibility/common/util/MediaPerfUtils.java[/url]
    /** Verifies |measuredFps| against reported achievable rates. Returns null if at least
* one measurement falls within the margins of the reported range. Otherwise, returns
* an error message to display.*/
public static String verifyAchievableFrameRates(
String name, String mime, int w, int h, double... measuredFps) {
Range<Double> reported =
MediaUtils.getVideoCapabilities(name, mime).getAchievableFrameRatesFor(w, h);
String kind = "achievable frame rates for " + name + " " + mime + " " + w + "x" + h;
if (reported == null) {
return "Failed to get " + kind;
}
double lowerBoundary1 = reported.getLower() / FRAMERATE_TOLERANCE;
double upperBoundary1 = reported.getUpper() * FRAMERATE_TOLERANCE;
double lowerBoundary2 = reported.getUpper() / Math.pow(FRAMERATE_TOLERANCE, 2);
double upperBoundary2 = reported.getLower() * Math.pow(FRAMERATE_TOLERANCE, 2);
Log.d(TAG, name + " " + mime + " " + w + "x" + h +
" lowerBoundary1 " + lowerBoundary1 + " upperBoundary1 " + upperBoundary1 +
" lowerBoundary2 " + lowerBoundary2 + " upperBoundary2 " + upperBoundary2 +
" measured " + Arrays.toString(measuredFps));

for (double measured : measuredFps) {
if (measured >= lowerBoundary1 && measured <= upperBoundary1
&& measured >= lowerBoundary2 && measured <= upperBoundary2) {
return null;
}
}

return "Expected " + kind + ": " + reported + ".\n"
+ "Measured frame rate: " + Arrays.toString(measuredFps) + ".\n";
}

找到对应测试里面的视频文件,该视频可以正常播放。这个视频解码相关的,因为是做高通的平台,高通扩展了自己的解码。优先会使用高通的解码器,所以我先做了这样的测试,优先高通的解码去掉,使用google原生解码的,发现同样失败了,所以继续分析。

再继续跟踪是定位到:
[url]http://androidxref.com/8.0.0_r4/xref/frameworks/base/media/java/android/media/MediaCodecInfo.java[/url]
        @Nullable
public Range<Double> getAchievableFrameRatesFor(int width, int height) {
if (!supports(width, height, null)) {
throw new IllegalArgumentException("unsupported size");
}

if (mMeasuredFrameRates == null || mMeasuredFrameRates.size() <= 0) {
Log.w(TAG, "Codec did not publish any measurement data.");
return null;
}

return estimateFrameRatesFor(width, height);
}

这个返回了size等于0,再接着分析mMeasuredFrameRates 是在getMeasuredFrameRates这个方法赋值的
        private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>();
final String prefix = "measured-frame-rate-";
Set<String> keys = map.keySet();
for (String key : keys) {
// looking for: measured-frame-rate-WIDTHxHEIGHT-range
if (!key.startsWith(prefix)) {
continue;
}
String subKey = key.substring(prefix.length());
String[] temp = key.split("-");
Log.w(TAG, key+ " : " + map.get(key));
if (temp.length != 5) {
continue;
}
String sizeStr = temp[3];
Size size = Utils.parseSize(sizeStr, null);
if (size == null || size.getWidth() * size.getHeight() <= 0) {
continue;
}
Range<Long> range = Utils.parseLongRange(map.get(key), null);
if(range !=null){
Log.w(TAG, "range== " + range.toString());
}
if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
continue;
}
Log.w(TAG, "put " +size.toString()+" : "+ range.toString());
ret.put(size, range);
}
Log.w(TAG, "getMeasuredFrameRates : "+ ret.size()+" "+mParent.getMimeType());
return ret;
}

这里注释写了是对measured-frame-rate-WIDTHxHEIGHT-range的解析。搜索一下measured-frame-rate-发现在/device/qcom/msm8909/media_codecs_performance.xml有这些
<Decoders>
<MediaCodec name="OMX.qcom.video.decoder.avc" type="video/avc" update="true">
<Limit name="measured-frame-rate-320x240" range="457-457" />
<Limit name="measured-frame-rate-720x480" range="274-274" />
<Limit name="measured-frame-rate-1280x720" range="168-168" />
<Limit name="measured-frame-rate-1920x1088" range="54-54" />
</MediaCodec>
....
</Decoders>

从测试机器里pull /vendor/etc/media_codecs_performance.xml。发现也是有OMX.qcom.video.decoder.avc。getMeasuredFrameRates的数据来源于media_codecs_performance.xml,该文件也提供了OMX.qcom.video.decoder.avc对应的配置,为何得到的mMeasuredFrameRates 未空呢?继续在MediaCodeInfo和MediaCodeList加debug信息发现,MediaCodeList会加载所有的media code信息(其来源于media_cocdes.xml和media_codecs_performance.xml),而一个media codec对应一个MediaCodeInfo,MediaCodeInfo又会包含多个CodecCapabilities,其他包含AudioCapabilities、VideoCapabilities、EncoderCapabilities。

将parseFromInfo中的要解析的MediaFormat打印出来发现其中确实没有包含"measured-frame-rate-"的信息。

01-02 08:10:44.007 910 910 E CodecCapabilities: mDefaultFormat: {mime=video/avc}

01-02 08:10:44.007 910 910 W VideoCapabilities: parseFromInfo:[color=red]{size-range=64x64-1920x1088, feature-adaptive-playback=0, bitrate-range=1-20000000, blocks-per-second-range=1-244800, alignment=2x2, max-concurrent-instances=8, feature-can-swap-width-height=0, block-size=16x16}[/color]
01-02 08:10:44.014 910 910 W VideoCapabilities: getMeasuredFrameRates : 0 video/avc
01-02 08:10:44.

并且发现了media_codecs_performance.xml中measured-frame-rate-320x240是以-分隔后长度是4,但在getMeasuredFrameRates的size是5,并且注释写measured-frame-rate-WIDTHxHEIGHT-range格式与xml文件不一致,所以推断是解析的时候进行了转换。最后找到了对xml解析的地方
[url]http://androidxref.com/8.0.0_r4/xref/frameworks/av/media/vndk/xmlparser/1.0/MediaCodecsXmlParser.cpp[/url]

针对这个解析才发现log提示了:
01-02 09:15:42.310 479 479 E MediaCodecsXmlParser: addMediaCodecFromAttributes: updating non-existing codec
01-02 09:15:42.310 479 479 W MediaCodecsXmlParser: parseTopLevelXMLFile(/vendor/etc/media_codecs_performance.xml) failed

解析media_codecs_performance.xml解析失败了,是由于updating non-existing codec。
继续加log定位解析到哪行失败了,最后发现是解析到:
        <MediaCodec name="OMX.google.vp9.encoder" type="video/x-vnd.on2.vp9" update="true">
<Limit name="measured-frame-rate-320x180" range="35-35" />
<Limit name="measured-frame-rate-640x360" range="10-10" />
<Limit name="measured-frame-rate-1280x720" range="5-5" />
</MediaCodec>


将"OMX.google.vp9.encoder"在media_codecs.xml和其include的media_codecs_google_video_le.xml查找,确实没有定义该encoder,所以会报updating non-existing codec。

[url]http://androidxref.com/8.0.0_r4/xref/frameworks/av/media/libstagefright/data/media_codecs_google_video_le.xml[/url]

最终解决方法是将:media_codecs_performance.xml中的OMX.google.vp9.encoder移除。

MediaCodecsXmlParser将media_codecs.xml和其include的media_codecs_google_video_le.xml和media_codecs_performance.xml的信息组合成MediaFormat信息供MediaCodecInfo使用。其结构类似这样
{size-range=64x64-1920x1088, feature-adaptive-playback=0, bitrate-range=1-20000000, blocks-per-second-range=1-244800, alignment=2x2, max-concurrent-instances=8, feature-can-swap-width-height=0, block-size=16x16}

MediaCodecsXmlParser中的addLimit通过如下代码

mCurrentType->second[std::string(a_name) + "-range"] = range;
将measured-frame-rate-WIDTHxHEIGHT拼接了-range,所以代码和前面的分析疑点对应起来了。

此外由于搭建CTS环境比较麻烦,需要跑测试部门找人帮忙验证该问题,这样debug起来非常困难和浪费时间,看了一下fail这部分的代码和其他牵扯比较少,所以我把相关代码抽出来写了单独的demo进行测试debug.


总结:1.由于以前没有接触过相关内容,所以靠从问题最终fail log一直反推分析定位问题及相关代码。如果有此相关经验早从其他log看到关键问题所在01-01 07:53:20.230 489 489 E MediaCodecsXmlParser: addMediaCodecFromAttributes: updating non-existing codec
01-01 07:53:20.231 489 489 W MediaCodecsXmlParser: parseTopLevelXMLFile(/vendor/etc/media_codecs_performance.xml) failed

反过来也是有好处的,通过问题能让你快速地理解某些知识点。
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值