CP MediaStress and MediaPreparer dynamic config changes to nougat

bug:33573055
bug:31443110
bug:32420751
Test: run cts -m CtsMediaStressTestCases
Change-Id: I96ce1be09f75b7ab75a9317fbf8f3a8f5e53bf0a
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
index c7acdcd..52294205 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
@@ -66,7 +66,7 @@
     void setPreparerWhitelist(Set<String> preparerWhitelist);
 
     /**
-     * Runs the module's precondition checks and setup tasks.
+     * Pushes dynamic configuration, then runs the module's precondition checks and setup tasks.
      * @param skipPrep whether preparation should be skipped
      * @param preconditionArgs arguments to set on precondition preparers for the module, taking
      * format arg-name:arg-value. If "arg-value" is unset, the value will default to "true".
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
index 5ed6870..d8a2adb 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
@@ -17,6 +17,7 @@
 
 import com.android.compatibility.common.tradefed.result.IModuleListener;
 import com.android.compatibility.common.tradefed.result.ModuleListener;
+import com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher;
 import com.android.compatibility.common.tradefed.targetprep.PreconditionPreparer;
 import com.android.compatibility.common.tradefed.targetprep.TokenRequirement;
 import com.android.compatibility.common.util.AbiUtils;
@@ -58,6 +59,7 @@
     private final IAbi mAbi;
     private final Set<String> mTokens = new HashSet<>();
     private IRemoteTest mTest = null;
+    private List<ITargetPreparer> mDynamicConfigPreparers = new ArrayList<>();
     private List<ITargetPreparer> mPreconditions = new ArrayList<>();
     private List<ITargetPreparer> mPreparers = new ArrayList<>();
     private List<ITargetCleaner> mCleaners = new ArrayList<>();
@@ -76,9 +78,11 @@
             if (preparer instanceof IAbiReceiver) {
                 hasAbiReceiver = true;
             }
-            // Separate preconditions from target preparers.
+            // Separate preconditions and dynamicconfigpushers from other target preparers.
             if (preparer instanceof PreconditionPreparer) {
                 mPreconditions.add(preparer);
+            }else if (preparer instanceof DynamicConfigPusher) {
+                mDynamicConfigPreparers.add(preparer);
             } else if (preparer instanceof TokenRequirement) {
                 mTokens.addAll(((TokenRequirement) preparer).getTokens());
             } else {
@@ -216,34 +220,16 @@
     @Override
     public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
         IModuleListener moduleListener = new ModuleListener(this, listener);
-
+        // Run DynamicConfigPusher setup once more, in case cleaner has previously
+        // removed dynamic config file from the target (see b/32877809)
+        for (ITargetPreparer preparer : mDynamicConfigPreparers) {
+            runPreparerSetup(preparer);
+        }
         // Setup
         for (ITargetPreparer preparer : mPreparers) {
-            String preparerName = preparer.getClass().getCanonicalName();
-            if (!mPreparerWhitelist.isEmpty() && !mPreparerWhitelist.contains(preparerName)) {
-                CLog.w("Skipping Preparer: %s since it is not in the whitelist %s",
-                        preparerName, mPreparerWhitelist);
-                continue;
-            }
-            CLog.d("Preparer: %s", preparer.getClass().getSimpleName());
-            if (preparer instanceof IAbiReceiver) {
-                ((IAbiReceiver) preparer).setAbi(mAbi);
-            }
-            try {
-                preparer.setUp(mDevice, mBuild);
-            } catch (BuildError e) {
-                // This should only happen for flashing new build
-                CLog.e("Unexpected BuildError from precondition: %s",
-                        preparer.getClass().getCanonicalName());
-            } catch (TargetSetupError e) {
-                // log precondition class then rethrow & let caller handle
-                CLog.e("TargetSetupError in precondition: %s",
-                        preparer.getClass().getCanonicalName());
-                throw new RuntimeException(e);
-            }
+            runPreparerSetup(preparer);
         }
 
-
         CLog.d("Test: %s", mTest.getClass().getSimpleName());
         if (mTest instanceof IAbiReceiver) {
             ((IAbiReceiver) mTest).setAbi(mAbi);
@@ -270,34 +256,51 @@
     @Override
     public boolean prepare(boolean skipPrep, List<String> preconditionArgs)
             throws DeviceNotAvailableException {
+        for (ITargetPreparer preparer : mDynamicConfigPreparers) {
+            runPreparerSetup(preparer);
+        }
         for (ITargetPreparer preparer : mPreconditions) {
-            CLog.d("Preparer: %s", preparer.getClass().getSimpleName());
-            if (preparer instanceof IAbiReceiver) {
-                ((IAbiReceiver) preparer).setAbi(mAbi);
-            }
             setOption(preparer, CompatibilityTest.SKIP_PRECONDITIONS_OPTION,
                     Boolean.toString(skipPrep));
             for (String preconditionArg : preconditionArgs) {
                 setOption(preparer, CompatibilityTest.PRECONDITION_ARG_OPTION, preconditionArg);
             }
             try {
-                preparer.setUp(mDevice, mBuild);
-            } catch (BuildError e) {
-                // This should only happen for flashing new build
-                CLog.e("Unexpected BuildError from precondition: %s",
-                        preparer.getClass().getCanonicalName());
-                return false;
-            } catch (TargetSetupError e) {
-                // log precondition class then rethrow & let caller handle
-                CLog.e("TargetSetupError in precondition: %s",
-                        preparer.getClass().getCanonicalName());
-                e.printStackTrace();
+                runPreparerSetup(preparer);
+            } catch (RuntimeException e) {
+                CLog.e("Precondition class %s failed", preparer.getClass().getCanonicalName());
                 return false;
             }
         }
         return true;
     }
 
+    private void runPreparerSetup(ITargetPreparer preparer) throws DeviceNotAvailableException {
+        String preparerName = preparer.getClass().getCanonicalName();
+        if (!mPreparerWhitelist.isEmpty() && !mPreparerWhitelist.contains(preparerName)) {
+            CLog.w("Skipping Preparer: %s since it is not in the whitelist %s",
+                    preparerName, mPreparerWhitelist);
+            return;
+        }
+        CLog.d("Preparer: %s", preparer.getClass().getSimpleName());
+        if (preparer instanceof IAbiReceiver) {
+            ((IAbiReceiver) preparer).setAbi(mAbi);
+        }
+        try {
+            preparer.setUp(mDevice, mBuild);
+        } catch (BuildError e) {
+            // This should only happen for flashing new build
+            CLog.e("Unexpected BuildError from preparer: %s",
+                    preparer.getClass().getCanonicalName());
+            throw new RuntimeException(e);
+        } catch (TargetSetupError e) {
+            // log preparer class then rethrow & let caller handle
+            CLog.e("TargetSetupError in preparer: %s",
+                    preparer.getClass().getCanonicalName());
+            throw new RuntimeException(e);
+        }
+    }
+
     private void setOption(Object target, String option, String value) {
         try {
             OptionSetter setter = new OptionSetter(target);
diff --git a/common/util/src/com/android/compatibility/common/util/DynamicConfig.java b/common/util/src/com/android/compatibility/common/util/DynamicConfig.java
index 8317203..d316b9d 100644
--- a/common/util/src/com/android/compatibility/common/util/DynamicConfig.java
+++ b/common/util/src/com/android/compatibility/common/util/DynamicConfig.java
@@ -29,6 +29,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Load dynamic config for test cases
@@ -67,6 +68,10 @@
         return mDynamicConfigMap.get(key);
     }
 
+    public Set<String> keySet() {
+        return mDynamicConfigMap.keySet();
+    }
+
     public static File getConfigFile(File configFolder, String moduleName)
             throws FileNotFoundException {
         File config =  new File(configFolder, String.format("%s.dynamic", moduleName));
diff --git a/libs/deviceutil/src/android/cts/util/MediaUtils.java b/libs/deviceutil/src/android/cts/util/MediaUtils.java
index 2c6aeae..56868a5 100644
--- a/libs/deviceutil/src/android/cts/util/MediaUtils.java
+++ b/libs/deviceutil/src/android/cts/util/MediaUtils.java
@@ -154,12 +154,11 @@
     public static void skipTest(String tag, String reason) {
         Log.i(tag, "SKIPPING " + getTestName() + "(): " + reason);
         DeviceReportLog log = new DeviceReportLog("CtsMediaSkippedTests", "test_skipped");
-        log.addValue("reason", reason, ResultType.NEUTRAL, ResultUnit.NONE);
-        log.addValue(
-                "test", getTestNameWithClass(), ResultType.NEUTRAL, ResultUnit.NONE);
-        // TODO: replace with submit() when it is added to DeviceReportLog
         try {
-            log.submit(null);
+            log.addValue("reason", reason, ResultType.NEUTRAL, ResultUnit.NONE);
+            log.addValue(
+                    "test", getTestNameWithClass(), ResultType.NEUTRAL, ResultUnit.NONE);
+            log.submit();
         } catch (NullPointerException e) { }
     }
 
diff --git a/tests/tests/mediastress/Android.mk b/tests/tests/mediastress/Android.mk
index 8667e68..4cbc4cc 100644
--- a/tests/tests/mediastress/Android.mk
+++ b/tests/tests/mediastress/Android.mk
@@ -26,7 +26,7 @@
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil compatibility-device-util
 
 LOCAL_HOST_SHARED_LIBRARIES := compatibility-device-media-preconditions
 
diff --git a/tests/tests/mediastress/AndroidTest.xml b/tests/tests/mediastress/AndroidTest.xml
index c01bbdf..a0cc68a 100644
--- a/tests/tests/mediastress/AndroidTest.xml
+++ b/tests/tests/mediastress/AndroidTest.xml
@@ -19,6 +19,10 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaStressTestCases.apk" />
     </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsMediaStressTestCases" />
+    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.mediastress.cts" />
         <!-- test-timeout unit is ms, value = 30 min -->
diff --git a/tests/tests/mediastress/DynamicConfig.xml b/tests/tests/mediastress/DynamicConfig.xml
new file mode 100644
index 0000000..2f8cfb0
--- /dev/null
+++ b/tests/tests/mediastress/DynamicConfig.xml
@@ -0,0 +1,347 @@
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<dynamicConfig>
+  <entry key="bbb_full_1280x720_mp4_libx264_libfaac_bbb_full_ffmpeg_1280x720_mp4_libx264_1350kbps_25fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_full_1280x720_mp4_libx264_libfaac_bbb_full_ffmpeg_1280x720_mp4_libx264_1750kbps_30fps_libfaac_stereo_192kbps_48000hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_full_1280x720_mp4_libx265_libfaac_bbb_full_ffmpeg_1280x720_mp4_libx265_1140kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,bitrate=999120,width=1280,height=720,frame-rate=30,profile=1,level=256;mime=audio/mp4a-latm,bitrate=127968,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_full_1280x720_mp4_libx265_libfaac_bbb_full_ffmpeg_1280x720_mp4_libx265_880kbps_24fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,bitrate=748632,width=1280,height=720,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,bitrate=127976,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_full_176x144_3gp_h263_libfaac_bbb_full_ffmpeg_176x144_3gp_h263_56kbps_12fps_libfaac_mono_24kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=1,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_full_1920x1080_mp4_libx264_libfaac_bbb_full_ffmpeg_1920x1080_mp4_libx264_10000kbps_30fps_libfaac_stereo_192kbps_48000hz_mp4">
+    <value>mime=video/avc,width=1920,height=1080,frame-rate=24,profile=1,level=4096;mime=audio/mp4a-latm,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_full_1920x1080_mp4_libx265_libfaac_bbb_full_ffmpeg_1920x1080_mp4_libx265_6500kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1920,height=1080,frame-rate=30,profile=1,level=1024;mime=audio/mp4a-latm,bitrate=128006,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_full_480x360_webm_libvpx_libvorbis_bbb_full_ffmpeg_480x360_webm_libvpx_500kbps_25fps_libvorbis_stereo_128kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_full_720x480_mp4_libx264_libfaac_bbb_full_ffmpeg_720x480_mp4_libx264_500kbps_25fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_full_720x480_mp4_libx265_libfaac_bbb_full_ffmpeg_720x480_mp4_libx265_325kbps_24fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,bitrate=280872,width=720,height=480,frame-rate=24,profile=1,level=64;mime=audio/mp4a-latm,bitrate=127976,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_1000kbps_25fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_1000kbps_25fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_1000kbps_30fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_1000kbps_30fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_1350kbps_25fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_1350kbps_25fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_1350kbps_30fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_1350kbps_30fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_1750kbps_30fps_libfaac_stereo_192kbps_48000hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_500kbps_25fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_500kbps_25fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_500kbps_30fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx264_libfaac_bbb_short_ffmpeg_1280x720_mp4_libx264_500kbps_30fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=1280,height=720,frame-rate=24,profile=1,level=512;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx265_libfaac_bbb_short_fmpeg_1280x720_mp4_libx265_1140kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1280,height=720,frame-rate=30,profile=1,level=256;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx265_libfaac_bbb_short_fmpeg_1280x720_mp4_libx265_3250kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1280,height=720,frame-rate=30,profile=1,level=256;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx265_libfaac_bbb_short_fmpeg_1280x720_mp4_libx265_325kbps_24fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1280,height=720,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,bitrate=129452,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx265_libfaac_bbb_short_fmpeg_1280x720_mp4_libx265_325kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1280,height=720,frame-rate=30,profile=1,level=256;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx265_libfaac_bbb_short_fmpeg_1280x720_mp4_libx265_6500kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1280,height=720,frame-rate=30,profile=1,level=256;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx265_libfaac_bbb_short_fmpeg_1280x720_mp4_libx265_650kbps_24fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1280,height=720,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,bitrate=129452,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx265_libfaac_bbb_short_fmpeg_1280x720_mp4_libx265_650kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1280,height=720,frame-rate=30,profile=1,level=256;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx265_libfaac_bbb_short_fmpeg_1280x720_mp4_libx265_880kbps_24fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1280,height=720,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,bitrate=129452,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1280x720_mp4_libx265_libfaac_bbb_short_fmpeg_1280x720_mp4_libx265_880kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1280,height=720,frame-rate=30,profile=1,level=256;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_300kbps_12fps_libfaac_mono_24kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=1,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_300kbps_12fps_libfaac_mono_24kbps_22050hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=22050,channel-count=1,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_300kbps_12fps_libfaac_stereo_128kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_300kbps_12fps_libfaac_stereo_128kbps_22050hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=22050,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_300kbps_12fps_libfaac_stereo_24kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_300kbps_12fps_libfaac_stereo_24kbps_22050hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=22050,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_300kbps_25fps_libfaac_mono_24kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=25,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=1,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_300kbps_25fps_libfaac_mono_24kbps_22050hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=25,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=22050,channel-count=1,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_300kbps_25fps_libfaac_stereo_128kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=25,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_300kbps_25fps_libfaac_stereo_128kbps_22050hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=25,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=22050,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_300kbps_25fps_libfaac_stereo_24kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=25,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_300kbps_25fps_libfaac_stereo_24kbps_22050hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=25,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=22050,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_56kbps_12fps_libfaac_mono_24kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=1,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_56kbps_12fps_libfaac_mono_24kbps_22050hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=22050,channel-count=1,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_56kbps_12fps_libfaac_stereo_128kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_56kbps_12fps_libfaac_stereo_128kbps_22050hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=22050,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_56kbps_12fps_libfaac_stereo_24kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_56kbps_12fps_libfaac_stereo_24kbps_22050hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=12,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=22050,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_56kbps_25fps_libfaac_mono_24kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=25,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=1,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_56kbps_25fps_libfaac_mono_24kbps_22050hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=25,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=22050,channel-count=1,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_56kbps_25fps_libfaac_stereo_128kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=25,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_56kbps_25fps_libfaac_stereo_128kbps_22050hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=25,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=22050,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_56kbps_25fps_libfaac_stereo_24kbps_11025hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=25,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=11025,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_176x144_3gp_h263_libfaac_bbb_short_ffmpeg_176x144_3gp_h263_56kbps_25fps_libfaac_stereo_24kbps_22050hz_3gp">
+    <value>mime=video/3gpp,width=176,height=144,frame-rate=25,profile=1,level=1;mime=audio/mp4a-latm,sample-rate=22050,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1920x1080_mp4_libx264_libfaac_bbb_short_ffmpeg_1920x1080_mp4_libx264_10000kbps_30fps_libfaac_stereo_192kbps_48000hz_mp4">
+    <value>mime=video/avc,width=1920,height=1080,frame-rate=24,profile=1,level=4096;mime=audio/mp4a-latm,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1920x1080_mp4_libx264_libfaac_bbb_short_ffmpeg_1920x1080_mp4_libx264_1750kbps_30fps_libfaac_stereo_192kbps_48000hz_mp4">
+    <value>mime=video/avc,width=1920,height=1080,frame-rate=24,profile=1,level=2048;mime=audio/mp4a-latm,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1920x1080_mp4_libx264_libfaac_bbb_short_ffmpeg_1920x1080_mp4_libx264_5000kbps_30fps_libfaac_stereo_192kbps_48000hz_mp4">
+    <value>mime=video/avc,width=1920,height=1080,frame-rate=24,profile=1,level=2048;mime=audio/mp4a-latm,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1920x1080_mp4_libx265_libfaac_bbb_short_fmpeg_1920x1080_mp4_libx265_1140kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1920,height=1080,frame-rate=30,profile=1,level=1024;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1920x1080_mp4_libx265_libfaac_bbb_short_fmpeg_1920x1080_mp4_libx265_3250kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1920,height=1080,frame-rate=30,profile=1,level=1024;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_1920x1080_mp4_libx265_libfaac_bbb_short_fmpeg_1920x1080_mp4_libx265_6500kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=1920,height=1080,frame-rate=30,profile=1,level=1024;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx264_libfaac_bbb_short_ffmpeg_480x360_mp4_libx264_1000kbps_25fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=480,height=360,frame-rate=24,profile=1,level=64;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx264_libfaac_bbb_short_ffmpeg_480x360_mp4_libx264_1000kbps_25fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=480,height=360,frame-rate=24,profile=1,level=64;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx264_libfaac_bbb_short_ffmpeg_480x360_mp4_libx264_1000kbps_30fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=480,height=360,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx264_libfaac_bbb_short_ffmpeg_480x360_mp4_libx264_1000kbps_30fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=480,height=360,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx264_libfaac_bbb_short_ffmpeg_480x360_mp4_libx264_1350kbps_25fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=480,height=360,frame-rate=24,profile=1,level=64;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx264_libfaac_bbb_short_ffmpeg_480x360_mp4_libx264_1350kbps_25fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=480,height=360,frame-rate=24,profile=1,level=64;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx264_libfaac_bbb_short_ffmpeg_480x360_mp4_libx264_1350kbps_30fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=480,height=360,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx264_libfaac_bbb_short_ffmpeg_480x360_mp4_libx264_1350kbps_30fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=480,height=360,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx264_libfaac_bbb_short_ffmpeg_480x360_mp4_libx264_500kbps_25fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=480,height=360,frame-rate=24,profile=1,level=64;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx264_libfaac_bbb_short_ffmpeg_480x360_mp4_libx264_500kbps_25fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=480,height=360,frame-rate=24,profile=1,level=64;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx264_libfaac_bbb_short_ffmpeg_480x360_mp4_libx264_500kbps_30fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=480,height=360,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx264_libfaac_bbb_short_ffmpeg_480x360_mp4_libx264_500kbps_30fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=480,height=360,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx265_libfaac_bbb_short_fmpeg_480x360_mp4_libx265_325kbps_24fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=640,height=480,frame-rate=24,profile=1,level=64;mime=audio/mp4a-latm,bitrate=129452,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx265_libfaac_bbb_short_fmpeg_480x360_mp4_libx265_325kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=640,height=480,frame-rate=30,profile=1,level=64;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx265_libfaac_bbb_short_fmpeg_480x360_mp4_libx265_650kbps_24fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=480,height=360,frame-rate=24,profile=1,level=16;mime=audio/mp4a-latm,bitrate=129452,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx265_libfaac_bbb_short_fmpeg_480x360_mp4_libx265_650kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=480,height=360,frame-rate=30,profile=1,level=16;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx265_libfaac_bbb_short_fmpeg_480x360_mp4_libx265_880kbps_24fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=480,height=360,frame-rate=24,profile=1,level=16;mime=audio/mp4a-latm,bitrate=129452,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_mp4_libx265_libfaac_bbb_short_fmpeg_480x360_mp4_libx265_880kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=480,height=360,frame-rate=30,profile=1,level=16;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_webm_libvpx_libvorbis_bbb_short_ffmpeg_480x360_webm_libvpx_1000kbps_25fps_libvorbis_stereo_128kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_webm_libvpx_libvorbis_bbb_short_ffmpeg_480x360_webm_libvpx_1000kbps_25fps_libvorbis_stereo_192kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_webm_libvpx_libvorbis_bbb_short_ffmpeg_480x360_webm_libvpx_1000kbps_30fps_libvorbis_stereo_128kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_webm_libvpx_libvorbis_bbb_short_ffmpeg_480x360_webm_libvpx_1000kbps_30fps_libvorbis_stereo_192kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_webm_libvpx_libvorbis_bbb_short_ffmpeg_480x360_webm_libvpx_1350kbps_25fps_libvorbis_stereo_128kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_webm_libvpx_libvorbis_bbb_short_ffmpeg_480x360_webm_libvpx_1350kbps_25fps_libvorbis_stereo_192kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_webm_libvpx_libvorbis_bbb_short_ffmpeg_480x360_webm_libvpx_1350kbps_30fps_libvorbis_stereo_128kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_webm_libvpx_libvorbis_bbb_short_ffmpeg_480x360_webm_libvpx_1350kbps_30fps_libvorbis_stereo_192kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_webm_libvpx_libvorbis_bbb_short_ffmpeg_480x360_webm_libvpx_500kbps_25fps_libvorbis_stereo_128kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_webm_libvpx_libvorbis_bbb_short_ffmpeg_480x360_webm_libvpx_500kbps_25fps_libvorbis_stereo_192kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_webm_libvpx_libvorbis_bbb_short_ffmpeg_480x360_webm_libvpx_500kbps_30fps_libvorbis_stereo_128kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_short_480x360_webm_libvpx_libvorbis_bbb_short_ffmpeg_480x360_webm_libvpx_500kbps_30fps_libvorbis_stereo_192kbps_44100hz_webm">
+    <value>mime=video/x-vnd.on2.vp8,width=480,height=360;mime=audio/vorbis,sample-rate=44100,channel-count=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx264_libfaac_bbb_short_ffmpeg_720x480_mp4_libx264_1000kbps_25fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx264_libfaac_bbb_short_ffmpeg_720x480_mp4_libx264_1000kbps_25fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx264_libfaac_bbb_short_ffmpeg_720x480_mp4_libx264_1000kbps_30fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx264_libfaac_bbb_short_ffmpeg_720x480_mp4_libx264_1000kbps_30fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx264_libfaac_bbb_short_ffmpeg_720x480_mp4_libx264_1350kbps_25fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx264_libfaac_bbb_short_ffmpeg_720x480_mp4_libx264_1350kbps_25fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx264_libfaac_bbb_short_ffmpeg_720x480_mp4_libx264_1350kbps_30fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx264_libfaac_bbb_short_ffmpeg_720x480_mp4_libx264_1350kbps_30fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx264_libfaac_bbb_short_ffmpeg_720x480_mp4_libx264_500kbps_25fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx264_libfaac_bbb_short_ffmpeg_720x480_mp4_libx264_500kbps_25fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx264_libfaac_bbb_short_ffmpeg_720x480_mp4_libx264_500kbps_30fps_libfaac_stereo_128kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx264_libfaac_bbb_short_ffmpeg_720x480_mp4_libx264_500kbps_30fps_libfaac_stereo_192kbps_44100hz_mp4">
+    <value>mime=video/avc,width=720,height=480,frame-rate=24,profile=1,level=256;mime=audio/mp4a-latm,sample-rate=44100,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx265_libfaac_bbb_short_fmpeg_720x480_mp4_libx265_325kbps_24fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=720,height=480,frame-rate=24,profile=1,level=64;mime=audio/mp4a-latm,bitrate=129452,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx265_libfaac_bbb_short_fmpeg_720x480_mp4_libx265_325kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=720,height=480,frame-rate=30,profile=1,level=64;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx265_libfaac_bbb_short_fmpeg_720x480_mp4_libx265_650kbps_24fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=720,height=480,frame-rate=24,profile=1,level=64;mime=audio/mp4a-latm,bitrate=129452,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx265_libfaac_bbb_short_fmpeg_720x480_mp4_libx265_650kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=720,height=480,frame-rate=30,profile=1,level=64;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx265_libfaac_bbb_short_fmpeg_720x480_mp4_libx265_880kbps_24fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=720,height=480,frame-rate=24,profile=1,level=64;mime=audio/mp4a-latm,bitrate=129452,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+  <entry key="bbb_short_720x480_mp4_libx265_libfaac_bbb_short_fmpeg_720x480_mp4_libx265_880kbps_30fps_libfaac_stereo_128kbps_48000hz_mp4">
+    <value>mime=video/hevc,width=720,height=480,frame-rate=30,profile=1,level=64;mime=audio/mp4a-latm,bitrate=128918,sample-rate=48000,channel-count=2,profile=2,aac-profile=2</value>
+  </entry>
+</dynamicConfig>
diff --git a/tests/tests/mediastress/preconditions/app/Android.mk b/tests/tests/mediastress/preconditions/app/Android.mk
new file mode 100644
index 0000000..b8aa32a
--- /dev/null
+++ b/tests/tests/mediastress/preconditions/app/Android.mk
@@ -0,0 +1,39 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctsdeviceutil
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PACKAGE_NAME := CtsMediaPreparerApp
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/mediastress/preconditions/app/AndroidManifest.xml b/tests/tests/mediastress/preconditions/app/AndroidManifest.xml
new file mode 100644
index 0000000..da8d3d2
--- /dev/null
+++ b/tests/tests/mediastress/preconditions/app/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.mediastress.cts.preconditions.app">
+
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="android.mediastress.cts.preconditions.app"
+            android:label="Device-side CTS mediastress preparation" />
+</manifest>
diff --git a/tests/tests/mediastress/preconditions/app/src/android/mediastress/cts/preconditions/app/MediaPreparerAppTest.java b/tests/tests/mediastress/preconditions/app/src/android/mediastress/cts/preconditions/app/MediaPreparerAppTest.java
new file mode 100644
index 0000000..9830cff
--- /dev/null
+++ b/tests/tests/mediastress/preconditions/app/src/android/mediastress/cts/preconditions/app/MediaPreparerAppTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.mediastress.cts.preconditions.app;
+
+import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+
+import android.app.Instrumentation;
+import android.cts.util.MediaUtils;
+import android.media.MediaFormat;
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Test class that uses device-side media APIs to determine up to which resolution MediaPreparer
+ * should copy media files for CtsMediaStressTestCases.
+ */
+@RunWith(JUnit4.class)
+public class MediaPreparerAppTest {
+
+    /** The module name used to retrieve Dynamic Configuration data */
+    private static final String MODULE_NAME = "CtsMediaStressTestCases";
+
+    /** The default (minimum) resolution of media file to copy to the device */
+    private static final int DEFAULT_MAX_WIDTH = 480;
+    private static final int DEFAULT_MAX_HEIGHT = 360;
+
+    /** Instrumentation status code used to write resolution to metrics */
+    private static final int INST_STATUS_IN_PROGRESS = 2;
+
+    /** Helper class for generating and retrieving width-height pairs */
+    private static final class Resolution {
+        // regex that matches a resolution string
+        private static final String PATTERN = "(\\d+)x(\\d+)";
+        // group indices for accessing resolution witdh/height from a Matcher created from PATTERN
+        private static final int WIDTH_INDEX = 1;
+        private static final int HEIGHT_INDEX = 2;
+
+        private final int width;
+        private final int height;
+
+        private Resolution(int width, int height) {
+            this.width = width;
+            this.height = height;
+        }
+
+        private Resolution(String resolution) {
+            Pattern pattern = Pattern.compile(PATTERN);
+            Matcher matcher = pattern.matcher(resolution);
+            matcher.find();
+            this.width = Integer.parseInt(matcher.group(WIDTH_INDEX));
+            this.height = Integer.parseInt(matcher.group(HEIGHT_INDEX));
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%dx%d", width, height);
+        }
+    }
+
+    @Test
+    public void testGetResolutions() throws Exception {
+        Resolution maxRes = new Resolution(DEFAULT_MAX_WIDTH, DEFAULT_MAX_HEIGHT);
+        DynamicConfigDeviceSide config = new DynamicConfigDeviceSide(MODULE_NAME);
+        for (String key : config.keySet()) {
+            int width = 0;
+            int height = 0;
+            for (MediaFormat format : stringsToFormats(config.getValues(key))) {
+                try {
+                    width = Math.max(width, format.getInteger(MediaFormat.KEY_WIDTH));
+                    height = Math.max(height, format.getInteger(MediaFormat.KEY_HEIGHT));
+                } catch (NullPointerException | ClassCastException e) {
+                    // audio format, or invalid format created by unrelated dynamic config entry
+                    // simply continue in this case
+                }
+            }
+            Resolution fileResolution = new Resolution(width, height);
+            // if the file is of greater resolution than maxRes, check for support
+            if (fileResolution.width > maxRes.width) {
+                boolean supported = true;
+                for (MediaFormat format : stringsToFormats(config.getValues(key))) {
+                    supported &= MediaUtils.checkDecoderForFormat(format);
+                }
+                if (supported) {
+                    // update if all MediaFormats for file are supported by device
+                    maxRes = fileResolution;
+                }
+            }
+        }
+        // write resolution string to metrics
+        Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+        Bundle maxResBundle = new Bundle();
+        maxResBundle.putString("resolution", maxRes.toString());
+        inst.sendStatus(INST_STATUS_IN_PROGRESS, maxResBundle);
+    }
+
+    /**
+     * Converts string representations of MediaFormats into actual MediaFormats
+     * @param formatStrings a list of string representations of MediaFormats. Each input string
+     * may represent one or more MediaFormats
+     * @return a list of MediaFormats
+     */
+    private List<MediaFormat> stringsToFormats(List<String> formatStrings) {
+        List<MediaFormat> formats = new ArrayList<MediaFormat>();
+        for (String formatString : formatStrings) {
+            for (String trackFormatString : formatString.split(";")) {
+                formats.add(parseTrackFormat(trackFormatString));
+            }
+        }
+        return formats;
+    }
+
+    /**
+     * Converts a single media track format string into a MediaFormat object
+     * @param trackFormatString a string representation of the format of one media track
+     * @return a MediaFormat
+     */
+    private static MediaFormat parseTrackFormat(String trackFormatString) {
+        MediaFormat format = new MediaFormat();
+        format.setString(MediaFormat.KEY_MIME, "");
+        for (String entry : trackFormatString.split(",")) {
+            String[] kv = entry.split("=");
+            if (kv.length < 2) {
+                continue;
+            }
+            String k = kv[0];
+            String v = kv[1];
+            try {
+                format.setInteger(k, Integer.parseInt(v));
+            } catch(NumberFormatException e) {
+                format.setString(k, v);
+            }
+        }
+        return format;
+    }
+}
diff --git a/tests/tests/mediastress/preconditions/src/android/mediastress/cts/preconditions/MediaPreparer.java b/tests/tests/mediastress/preconditions/src/android/mediastress/cts/preconditions/MediaPreparer.java
index f4ac511..a780317 100644
--- a/tests/tests/mediastress/preconditions/src/android/mediastress/cts/preconditions/MediaPreparer.java
+++ b/tests/tests/mediastress/preconditions/src/android/mediastress/cts/preconditions/MediaPreparer.java
@@ -15,25 +15,31 @@
  */
 package android.mediastress.cts.preconditions;
 
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.tradefed.targetprep.PreconditionPreparer;
 import com.android.compatibility.common.util.DynamicConfigHostSide;
 import com.android.ddmlib.IDevice;
+import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.Option;
 import com.android.tradefed.config.OptionClass;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.StubTestInvocationListener;
 import com.android.tradefed.targetprep.BuildError;
 import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.testtype.AndroidJUnitTest;
 import com.android.tradefed.util.FileUtil;
 import com.android.tradefed.util.ZipUtil;
 
-import java.awt.Dimension;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.io.IOException;
 import java.net.URL;
 import java.net.URLConnection;
+import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.zip.ZipFile;
@@ -56,6 +62,26 @@
     protected boolean mSkipMediaDownload = false;
 
     /*
+     * The pathnames of the device's directories that hold media files for the tests.
+     * These depend on the device's mount point, which is retrieved in the MediaPreparer's run
+     * method.
+     *
+     * These fields are exposed for unit testing
+     */
+    protected String mBaseDeviceShortDir;
+    protected String mBaseDeviceFullDir;
+
+    /*
+     * Variables set by the MediaPreparerListener during retrieval of maximum media file
+     * resolution. After the MediaPreparerApp has been instrumented on the device:
+     *
+     * testMetrics contains the string representation of the resolution
+     * testFailures contains a stacktrace if retrieval of the resolution was unsuccessful
+     */
+    protected Resolution mMaxRes = null;
+    protected String mFailureStackTrace = null;
+
+    /*
      * The default name of local directory into which media files will be downloaded, if option
      * "local-media-path" is not provided. This directory will live inside the temp directory.
      */
@@ -68,99 +94,52 @@
     private static final String DYNAMIC_CONFIG_MODULE = "cts";
 
     /*
-     * The message printed when the maximum video playback resolution cannot be found in the
-     * output of 'dumpsys'. When this is the case, media files of all resolutions must be pushed
-     * to the device.
+     * Info used to install and uninstall the MediaPreparerApp
      */
-    private static final String MAX_PLAYBACK_RES_FAILURE_MSG =
-            "Unable to parse maximum video playback resolution, pushing all media files";
+    private static final String APP_APK = "CtsMediaPreparerApp.apk";
+    private static final String APP_PKG_NAME = "android.mediastress.cts.preconditions.app";
 
-    private static final String LOG_TAG = MediaPreparer.class.getSimpleName();
+    /* Key to retrieve resolution string in metrics upon MediaPreparerListener.testEnded() */
+    private static final String RESOLUTION_STRING_KEY = "resolution";
 
-    /* Constants identifying resolutions of the media files to be copied */
-    protected static final int RES_176_144 = 0; // 176x144 resolution
-    protected static final int RES_DEFAULT = 1; // default max video playback resolution, 480x360
-    protected static final int RES_720_480 = 2; // 720x480 resolution
-    protected static final int RES_1280_720 = 3; // 1280x720 resolution
-    protected static final int RES_1920_1080 = 4; // 1920x1080 resolution
+    protected static final Resolution DEFAULT_MAX_RESOLUTION = new Resolution(480, 360);
 
-    protected static final Dimension[] resolutions = { // indices meant to align with constants above
-            new Dimension(176, 144),
-            new Dimension(480, 360),
-            new Dimension(720, 480),
-            new Dimension(1280, 720),
-            new Dimension(1920, 1080)
+    protected static final Resolution[] RESOLUTIONS = {
+            new Resolution(176, 144),
+            new Resolution(480, 360),
+            new Resolution(720, 480),
+            new Resolution(1280, 720),
+            new Resolution(1920, 1080)
     };
 
-    /*
-     * The pathnames of the device's directories that hold media files for the tests.
-     * These depend on the device's mount point, which is retrieved in the MediaPreparer's run
-     * method.
-     *
-     * These fields are exposed for unit testing
-     */
-    protected String mBaseDeviceShortDir;
-    protected String mBaseDeviceFullDir;
+    /** Helper class for generating and retrieving width-height pairs */
+    protected static final class Resolution {
+        // regex that matches a resolution string
+        private static final String PATTERN = "(\\d+)x(\\d+)";
+        // group indices for accessing resolution width and height from a PATTERN-based Matcher
+        private static final int WIDTH_INDEX = 1;
+        private static final int HEIGHT_INDEX = 2;
 
-    /*
-     * Returns a string representation of the dimension
-     * For dimension of width = 480 and height = 360, the resolution string is "480x360"
-     */
-    private static String resolutionString(Dimension resolution) {
-        return String.format("%dx%d", resolution.width, resolution.height);
-    }
+        private final int width;
+        private final int height;
 
-    /*
-     * Loops through the predefined maximum video playback resolutions from largest to smallest,
-     * And returns the greatest resolution that is strictly smaller than the width and height
-     * provided in the arguments
-     */
-    private Dimension getMaxVideoPlaybackResolution(int width, int height) {
-        for (int resIndex = resolutions.length - 1; resIndex >= RES_DEFAULT; resIndex--) {
-            Dimension resolution = resolutions[resIndex];
-            if (width >= resolution.width && height >= resolution.height) {
-                return resolution;
-            }
-        }
-        return resolutions[RES_DEFAULT];
-    }
-
-    /*
-     * Returns the maximum video playback resolution of the device, in the form of a Dimension
-     * object. This method parses dumpsys output to find resolutions listed under the
-     * 'mBaseDisplayInfo' field. The value for 'smallest app' is used as an estimate for
-     * maximum video playback resolution, and is rounded down to the nearest dimension in the
-     * resolutions array.
-     *
-     * This method is exposed for unit testing.
-     */
-    protected Dimension getMaxVideoPlaybackResolution(ITestDevice device)
-            throws DeviceNotAvailableException {
-        String dumpsysOutput =
-                device.executeShellCommand("dumpsys display | grep mBaseDisplayInfo");
-        Pattern pattern = Pattern.compile("smallest app (\\d+) x (\\d+)");
-        Matcher matcher = pattern.matcher(dumpsysOutput);
-        if(!matcher.find()) {
-            // could not find resolution in dumpsysOutput, return largest max playback resolution
-            // so that preparer copies all media files
-            logError(MAX_PLAYBACK_RES_FAILURE_MSG);
-            return resolutions[RES_1920_1080];
+        private Resolution(int width, int height) {
+            this.width = width;
+            this.height = height;
         }
 
-        int first;
-        int second;
-        try {
-            first = Integer.parseInt(matcher.group(1));
-            second = Integer.parseInt(matcher.group(2));
-        } catch (NumberFormatException e) {
-            logError(MAX_PLAYBACK_RES_FAILURE_MSG);
-            return resolutions[RES_1920_1080];
+        private Resolution(String resolution) {
+            Pattern pattern = Pattern.compile(PATTERN);
+            Matcher matcher = pattern.matcher(resolution);
+            matcher.find();
+            this.width = Integer.parseInt(matcher.group(WIDTH_INDEX));
+            this.height = Integer.parseInt(matcher.group(HEIGHT_INDEX));
         }
-        // dimensions in dumpsys output seem consistently reversed
-        // here we make note of which dimension is the larger of the two
-        int height = Math.min(first, second);
-        int width = Math.max(first, second);
-        return getMaxVideoPlaybackResolution(width, height);
+
+        @Override
+        public String toString() {
+            return String.format("%dx%d", width, height);
+        }
     }
 
     /*
@@ -168,22 +147,18 @@
      *
      * This method is exposed for unit testing.
      */
-    protected boolean mediaFilesExistOnDevice(ITestDevice device, Dimension mvpr)
-            throws DeviceNotAvailableException{
-        int resIndex = RES_176_144;
-        while (resIndex <= RES_1920_1080) {
-            Dimension copiedResolution = resolutions[resIndex];
-            if (copiedResolution.width > mvpr.width || copiedResolution.height > mvpr.height) {
-                break; // we don't need to check for resolutions greater than or equal to this
+    protected boolean mediaFilesExistOnDevice(ITestDevice device)
+            throws DeviceNotAvailableException {
+        for (Resolution resolution : RESOLUTIONS) {
+            if (resolution.width > mMaxRes.width) {
+                break; // no need to check for resolutions greater than this
             }
-            String resString = resolutionString(copiedResolution);
-            String deviceShortFilePath = mBaseDeviceShortDir + resString;
-            String deviceFullFilePath = mBaseDeviceFullDir + resString;
-            if (!device.doesFileExist(deviceShortFilePath) ||
-                    !device.doesFileExist(deviceFullFilePath)) { // media files must be copied
+            String deviceShortFilePath = mBaseDeviceShortDir + resolution.toString();
+            String deviceFullFilePath = mBaseDeviceFullDir + resolution.toString();
+            if (!device.doesFileExist(deviceShortFilePath)
+                    || !device.doesFileExist(deviceFullFilePath)) {
                 return false;
             }
-            resIndex++;
         }
         return true;
     }
@@ -212,7 +187,6 @@
      * bbb_full media directories.
      */
     private void downloadMediaToHost(File mediaFolder) throws TargetSetupError {
-
         URL url;
         try {
             // Get download URL from dynamic configuration service
@@ -223,7 +197,6 @@
             throw new TargetSetupError("Trouble finding media file download location with " +
                     "dynamic configuration", e);
         }
-
         File mediaFolderZip = new File(mediaFolder.getAbsolutePath() + ".zip");
         try {
             logInfo("Downloading media files from %s", url.toString());
@@ -233,7 +206,6 @@
             FileUtil.writeToFile(in, mediaFolderZip);
             logInfo("Unzipping media files");
             ZipUtil.extractZip(new ZipFile(mediaFolderZip), mediaFolder);
-
         } catch (IOException e) {
             FileUtil.recursiveDelete(mediaFolder);
             throw new TargetSetupError("Failed to download and open media files on host, the"
@@ -251,25 +223,20 @@
      *
      * This method is exposed for unit testing.
      */
-    protected void copyMediaFiles(ITestDevice device, Dimension mvpr)
+    protected void copyMediaFiles(ITestDevice device)
             throws DeviceNotAvailableException {
-
-        int resIndex = RES_176_144;
-        while (resIndex <= RES_1920_1080) {
-            Dimension copiedResolution = resolutions[resIndex];
-            String resString = resolutionString(copiedResolution);
-            if (copiedResolution.width > mvpr.width || copiedResolution.height > mvpr.height) {
-                logInfo("Device cannot support resolutions %s and larger, media copying complete",
-                        resString);
+        for (Resolution resolution : RESOLUTIONS) {
+            if (resolution.width > mMaxRes.width) {
+                logInfo("Media file copying complete");
                 return;
             }
-            String deviceShortFilePath = mBaseDeviceShortDir + resString;
-            String deviceFullFilePath = mBaseDeviceFullDir + resString;
+            String deviceShortFilePath = mBaseDeviceShortDir + resolution.toString();
+            String deviceFullFilePath = mBaseDeviceFullDir + resolution.toString();
             if (!device.doesFileExist(deviceShortFilePath) ||
                     !device.doesFileExist(deviceFullFilePath)) {
-                logInfo("Copying files of resolution %s to device", resString);
-                String localShortDirName = "bbb_short/" + resString;
-                String localFullDirName = "bbb_full/" + resString;
+                logInfo("Copying files of resolution %s to device", resolution.toString());
+                String localShortDirName = "bbb_short/" + resolution.toString();
+                String localFullDirName = "bbb_full/" + resolution.toString();
                 File localShortDir = new File(mLocalMediaPath, localShortDirName);
                 File localFullDir = new File(mLocalMediaPath, localFullDirName);
                 // push short directory of given resolution, if not present on device
@@ -281,7 +248,6 @@
                     device.pushDir(localFullDir, deviceFullFilePath);
                 }
             }
-            resIndex++;
         }
     }
 
@@ -300,15 +266,13 @@
             logInfo("Skipping media preparation");
             return; // skip this precondition
         }
-
         setMountPoint(device);
-        Dimension mvpr = getMaxVideoPlaybackResolution(device);
-        if (mediaFilesExistOnDevice(device, mvpr)) {
+        setMaxRes(device, buildInfo);
+        if (mediaFilesExistOnDevice(device)) {
             // if files already on device, do nothing
             logInfo("Media files found on the device");
             return;
         }
-
         if (mLocalMediaPath == null) {
             // Option 'local-media-path' has not been defined
             // Get directory to store media files on this host
@@ -323,9 +287,62 @@
             // set mLocalMediaPath to where the CTS media files have been extracted
             updateLocalMediaPath(mediaFolder);
         }
-
         logInfo("Media files located on host at: %s", mLocalMediaPath);
-        copyMediaFiles(device, mvpr);
+        copyMediaFiles(device);
     }
 
+    // Initialize maximum resolution of media files to copy
+    private void setMaxRes(ITestDevice device, IBuildInfo buildInfo)
+            throws DeviceNotAvailableException {
+        ITestInvocationListener listener = new MediaPreparerListener();
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
+        File apkFile = null;
+        try {
+            apkFile = new File(buildHelper.getTestsDir(), APP_APK);
+            if (!apkFile.exists()) {
+                // handle both missing tests dir and missing APK in catch block
+                throw new FileNotFoundException();
+            }
+        } catch (FileNotFoundException e) {
+            mMaxRes = DEFAULT_MAX_RESOLUTION;
+            logWarning("Cound not find %s to determine maximum resolution, copying up to %s",
+                    APP_APK, DEFAULT_MAX_RESOLUTION.toString());
+            return;
+        }
+        if (device.getAppPackageInfo(APP_PKG_NAME) != null) {
+            device.uninstallPackage(APP_PKG_NAME);
+        }
+        logInfo("Instrumenting package %s:", APP_PKG_NAME);
+        AndroidJUnitTest instrTest = new AndroidJUnitTest();
+        instrTest.setDevice(device);
+        instrTest.setInstallFile(apkFile);
+        instrTest.setPackageName(APP_PKG_NAME);
+        instrTest.run(listener);
+        if (mFailureStackTrace != null) {
+            mMaxRes = DEFAULT_MAX_RESOLUTION;
+            logWarning("Retrieving maximum resolution failed with trace:\n%s", mFailureStackTrace);
+            logWarning("Copying up to %s", DEFAULT_MAX_RESOLUTION.toString());
+        } else if (mMaxRes == null) {
+            mMaxRes = DEFAULT_MAX_RESOLUTION;
+            logWarning("Failed to pull resolution capabilities from device, copying up to %s",
+                    DEFAULT_MAX_RESOLUTION.toString());
+        }
+    }
+
+    /* Special listener for setting MediaPreparer instance variable values */
+    private class MediaPreparerListener extends StubTestInvocationListener {
+
+        @Override
+        public void testEnded(TestIdentifier test, Map<String, String> metrics) {
+            String resString = metrics.get(RESOLUTION_STRING_KEY);
+            if (resString != null) {
+                mMaxRes = new Resolution(resString);
+            }
+        }
+
+        @Override
+        public void testFailed(TestIdentifier test, String trace) {
+            mFailureStackTrace = trace;
+        }
+    }
 }
diff --git a/tests/tests/mediastress/preconditions/tests/src/android/mediastress/cts/preconditions/MediaPreparerTest.java b/tests/tests/mediastress/preconditions/tests/src/android/mediastress/cts/preconditions/MediaPreparerTest.java
index 4f71069..04c3900 100644
--- a/tests/tests/mediastress/preconditions/tests/src/android/mediastress/cts/preconditions/MediaPreparerTest.java
+++ b/tests/tests/mediastress/preconditions/tests/src/android/mediastress/cts/preconditions/MediaPreparerTest.java
@@ -23,8 +23,6 @@
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.targetprep.TargetSetupError;
 
-import java.awt.Dimension;
-
 import junit.framework.TestCase;
 
 import org.easymock.EasyMock;
@@ -36,9 +34,6 @@
     private ITestDevice mMockDevice;
     private OptionSetter mOptionSetter;
 
-    private final Dimension DEFAULT_DIMENSION =
-            MediaPreparer.resolutions[MediaPreparer.RES_DEFAULT];
-
     @Override
     public void setUp() throws Exception {
         super.setUp();
@@ -58,53 +53,44 @@
     }
 
     public void testCopyMediaFiles() throws Exception {
-        // by jumping directly into copyMediaFiles, the baseDeviceShortDir variable won't be set
-        // thus, the string "null" replaces the variable
-        EasyMock.expect(mMockDevice.doesFileExist("null176x144")).andReturn(true).anyTimes();
-        EasyMock.expect(mMockDevice.doesFileExist("null480x360")).andReturn(true).anyTimes();
+        mMediaPreparer.mMaxRes = MediaPreparer.DEFAULT_MAX_RESOLUTION;
+        mMediaPreparer.mBaseDeviceShortDir = "/sdcard/test/bbb_short/";
+        mMediaPreparer.mBaseDeviceFullDir = "/sdcard/test/bbb_full/";
+        for (MediaPreparer.Resolution resolution : MediaPreparer.RESOLUTIONS) {
+            String shortFile = String.format("%s%s", mMediaPreparer.mBaseDeviceShortDir,
+                    resolution.toString());
+            String fullFile = String.format("%s%s", mMediaPreparer.mBaseDeviceFullDir,
+                    resolution.toString());
+            EasyMock.expect(mMockDevice.doesFileExist(shortFile)).andReturn(true).once();
+            EasyMock.expect(mMockDevice.doesFileExist(fullFile)).andReturn(true).once();
+        }
         EasyMock.replay(mMockDevice);
-        mMediaPreparer.copyMediaFiles(mMockDevice, DEFAULT_DIMENSION);
+        mMediaPreparer.copyMediaFiles(mMockDevice);
     }
 
     public void testMediaFilesExistOnDeviceTrue() throws Exception {
-        // by jumping directly into copyMediaFiles, the baseDeviceShortDir variable won't be set
-        // thus, the string "null" replaces the variable
-        EasyMock.expect(mMockDevice.doesFileExist("null176x144")).andReturn(true).anyTimes();
-        EasyMock.expect(mMockDevice.doesFileExist("null480x360")).andReturn(true).anyTimes();
+        mMediaPreparer.mMaxRes = MediaPreparer.DEFAULT_MAX_RESOLUTION;
+        mMediaPreparer.mBaseDeviceShortDir = "/sdcard/test/bbb_short/";
+        mMediaPreparer.mBaseDeviceFullDir = "/sdcard/test/bbb_full/";
+        for (MediaPreparer.Resolution resolution : MediaPreparer.RESOLUTIONS) {
+            String shortFile = String.format("%s%s", mMediaPreparer.mBaseDeviceShortDir,
+                    resolution.toString());
+            String fullFile = String.format("%s%s", mMediaPreparer.mBaseDeviceFullDir,
+                    resolution.toString());
+            EasyMock.expect(mMockDevice.doesFileExist(shortFile)).andReturn(true).anyTimes();
+            EasyMock.expect(mMockDevice.doesFileExist(fullFile)).andReturn(true).anyTimes();
+        }
         EasyMock.replay(mMockDevice);
-        assertTrue(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice, DEFAULT_DIMENSION));
+        assertTrue(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice));
     }
 
     public void testMediaFilesExistOnDeviceFalse() throws Exception {
-        // by jumping directly into copyMediaFiles, the baseDeviceShortDir variable won't be set
-        // thus, the string "null" replaces the variable
-        EasyMock.expect(mMockDevice.doesFileExist("null176x144")).andReturn(false).anyTimes();
-        EasyMock.expect(mMockDevice.doesFileExist("null480x360")).andReturn(true).anyTimes();
+        mMediaPreparer.mMaxRes = MediaPreparer.DEFAULT_MAX_RESOLUTION;
+        mMediaPreparer.mBaseDeviceShortDir = "/sdcard/test/bbb_short/";
+        String firstFileChecked = "/sdcard/test/bbb_short/176x144";
+        EasyMock.expect(mMockDevice.doesFileExist(firstFileChecked)).andReturn(false).once();
         EasyMock.replay(mMockDevice);
-        assertFalse(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice, DEFAULT_DIMENSION));
-    }
-
-    public void testGetMaxVideoPlaybackResolutionFound() throws Exception {
-        String mockDumpsysOutput = "mBaseDisplayInfo=DisplayInfo{\"Built-in Screen\", uniqueId " +
-                "\"local:0\", app 1440 x 2560, real 1440 x 2560, largest app 1440 x 2560, " +
-                "smallest app 360 x 480, mode 1, defaultMode 1, modes [{id=1, width=1440, " +
-                "height=2560, fps=60.0}], rotation 0, density 560 (494.27 x 492.606) dpi, " +
-                "layerStack 0, appVsyncOff 2500000, presDeadline 17666667, type BUILT_IN, state " +
-                "ON, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS}\n";
-        EasyMock.expect(mMockDevice.executeShellCommand(
-                "dumpsys display | grep mBaseDisplayInfo")).andReturn(mockDumpsysOutput).once();
-        EasyMock.replay(mMockDevice);
-        Dimension result = mMediaPreparer.getMaxVideoPlaybackResolution(mMockDevice);
-        assertEquals(result, DEFAULT_DIMENSION);
-    }
-
-    public void testGetMaxVideoPlaybackResolutionNotFound() throws Exception {
-        String mockDumpsysOutput = "incorrect output";
-        EasyMock.expect(mMockDevice.executeShellCommand(
-                "dumpsys display | grep mBaseDisplayInfo")).andReturn(mockDumpsysOutput).once();
-        EasyMock.replay(mMockDevice);
-        Dimension result = mMediaPreparer.getMaxVideoPlaybackResolution(mMockDevice);
-        assertEquals(result, MediaPreparer.resolutions[MediaPreparer.RES_1920_1080]);
+        assertFalse(mMediaPreparer.mediaFilesExistOnDevice(mMockDevice));
     }
 
     public void testSkipMediaDownload() throws Exception {
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java b/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
index b33451b..400aedf 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/MediaPlayerStressTest.java
@@ -16,10 +16,13 @@
 
 package android.mediastress.cts;
 
+import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Intent;
 import android.cts.util.MediaUtils;
+import android.media.MediaFormat;
 import android.media.MediaRecorder.AudioEncoder;
 import android.media.MediaRecorder.VideoEncoder;
 import android.os.Environment;
@@ -30,6 +33,8 @@
 import java.io.File;
 import java.io.FileWriter;
 import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
 
 import android.test.InstrumentationTestCase;
 
@@ -42,6 +47,7 @@
     protected static final int REPEAT_NUMBER_FOR_LONG_CLIPS = 1;
     protected static final int REPEAT_NUMBER_FOR_REPEATED_PLAYBACK = 20;
     private static final String TAG = "MediaPlayerStressTest";
+    private static final String MODULE_NAME = "CtsMediaStressTestCases";
 
     /**
      * provides full path name of video clip for the given media number
@@ -96,6 +102,48 @@
         mTotalMetaDataUpdate += CodecTest.mMediaInfoMetdataUpdateCount;
     }
 
+    private static MediaFormat parseTrackFormat(String trackFormatString) {
+        MediaFormat format = new MediaFormat();
+        format.setString(MediaFormat.KEY_MIME, "");
+
+        for (String entry : trackFormatString.split(",")) {
+            String[] kv = entry.split("=");
+            if (kv.length < 2) {
+                continue;
+            }
+
+            String k = kv[0];
+            String v = kv[1];
+            try {
+                format.setInteger(k, Integer.parseInt(v));
+            } catch(NumberFormatException e) {
+                format.setString(k, v);
+            }
+        }
+
+        return format;
+    }
+
+    private List<MediaFormat> getClipFormats(String mediaName) throws Exception {
+        List<MediaFormat> mediaFormats = new ArrayList<MediaFormat>();
+        DynamicConfigDeviceSide config = new DynamicConfigDeviceSide(MODULE_NAME);
+        String[] components = mediaName.split(VIDEO_TOP_DIR);
+        String key = mediaNameToKey(components[components.length -1]);
+        List<String> mediaFormatStrings = config.getValues(key);
+        for (String mediaFormatString : mediaFormatStrings) {
+            String[] trackFormatStrings = mediaFormatString.split(";");
+            for (String trackFormatString : trackFormatStrings) {
+                MediaFormat format = parseTrackFormat(trackFormatString);
+                mediaFormats.add(format);
+            }
+        }
+        return mediaFormats;
+    }
+
+    private String mediaNameToKey(String mediaName) {
+        return mediaName.replaceAll("[\\./]", "_").toLowerCase();
+    }
+
     /**
      * runs video playback test for the given mediaNumber
      * @param mediaNumber number of media to be used for playback.
@@ -106,8 +154,12 @@
     protected void doTestVideoPlayback(int mediaNumber, int repeatCounter) throws Exception {
         Instrumentation inst = getInstrumentation();
         String mediaName = getFullVideoClipName(mediaNumber);
-        if (!MediaUtils.checkCodecsForPath(inst.getTargetContext(), mediaName)) {
-            return;  // not supported, message is already logged
+        for (MediaFormat format: getClipFormats(mediaName)) {
+            if (!MediaUtils.checkDecoderForFormat(format)) {
+                Log.i(TAG, "skipping " + this.getClass().getSimpleName()
+                    + " test clip " + mediaName + " format " + format);
+                return;  // not supported
+            }
         }
 
         File playbackOutput = new File(WorkDir.getTopDir(), "PlaybackTestResult.txt");
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index c74615c..7983c75 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -135,8 +135,6 @@
 
     <!-- b/25850508 -->
     <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testCopyMediaFiles" />
-    <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testGetMaxVideoPlaybackResolutionFound" />
-    <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testGetMaxVideoPlaybackResolutionNotFound" />
     <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testMediaFilesExistOnDeviceFalse" />
     <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testMediaFilesExistOnDeviceTrue" />
     <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases android.mediastress.cts.preconditions.MediaPreparerTest#testSetMountPoint" />