1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media.decoder.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertTrue; 22 import static org.junit.Assert.fail; 23 24 import android.app.Instrumentation; 25 import android.content.res.AssetFileDescriptor; 26 import android.content.res.Resources; 27 import android.media.MediaCodec; 28 import android.media.MediaCodecInfo; 29 import android.media.MediaCodecList; 30 import android.media.MediaExtractor; 31 import android.media.MediaFormat; 32 import android.media.cts.TestUtils; 33 import android.media.decoder.cts.DecoderTest.AudioParameter; 34 import android.media.decoder.cts.DecoderTestAacDrc.DrcParams; 35 import android.os.Build; 36 import android.os.Bundle; 37 import android.platform.test.annotations.AppModeFull; 38 import android.util.Log; 39 40 import androidx.test.InstrumentationRegistry; 41 42 import com.android.compatibility.common.util.ApiLevelUtil; 43 import com.android.compatibility.common.util.ApiTest; 44 import com.android.compatibility.common.util.CddTest; 45 import com.android.compatibility.common.util.MediaUtils; 46 47 import org.junit.Before; 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 import org.junit.runners.JUnit4; 51 52 import java.io.IOException; 53 import java.nio.ByteBuffer; 54 import java.util.ArrayList; 55 import java.util.Arrays; 56 import java.util.List; 57 58 @AppModeFull(reason = "DecoderTest is non-instant") 59 @RunWith(JUnit4.class) 60 public class DecoderTestXheAac { 61 private static final String TAG = "DecoderTestXheAac"; 62 63 private static final boolean sIsAndroidRAndAbove = 64 ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R); 65 66 private Resources mResources; 67 68 // list of all AAC decoders as enumerated through the MediaCodecList 69 // lazy initialization in setUp() 70 private static ArrayList<String> sAacDecoderNames; 71 private static String defaultAacDecoder = null; 72 @Before setUp()73 public void setUp() throws Exception { 74 final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); 75 assertNotNull(inst); 76 mResources = inst.getContext().getResources(); 77 // build a list of all AAC decoders on which to run the test 78 if (sAacDecoderNames == null) { 79 sAacDecoderNames = initAacDecoderNames(); 80 } 81 } 82 initAacDecoderNames()83 protected static ArrayList<String> initAacDecoderNames() throws IOException { 84 ArrayList<String> aacDecoderNames = new ArrayList<String>(1); 85 // Default aac decoder (the one that gets created when createDecoderByType with AAC mime 86 // is called) is expected to pass all DRC tests 87 if (defaultAacDecoder != null) { 88 aacDecoderNames.add(defaultAacDecoder); 89 } else { 90 MediaCodec decoder = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_AUDIO_AAC); 91 aacDecoderNames.add(decoder.getName()); 92 defaultAacDecoder = decoder.getName(); 93 decoder.release(); 94 } 95 // Add all decoders that advertise support for AACObjectXHE profile as decoders that 96 // support xHE-AAC profile are expected to support DRC 97 MediaFormat format = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 48000, 98 2); 99 // Set both KEY_AAC_PROFILE and KEY_PROFILE as some codecs may only recognize one of 100 // these two keys 101 format.setInteger(MediaFormat.KEY_AAC_PROFILE, 102 MediaCodecInfo.CodecProfileLevel.AACObjectXHE); 103 format.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectXHE); 104 105 final MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS); 106 final MediaCodecInfo[] mediaCodecInfos = mediaCodecList.getCodecInfos(); 107 for (MediaCodecInfo mediaCodecInfo : mediaCodecInfos) { 108 if (mediaCodecInfo.isAlias()) { 109 continue; 110 } 111 if (mediaCodecInfo.isEncoder()) { 112 continue; 113 } 114 final String codecName = mediaCodecInfo.getName(); 115 final String[] mimeTypes = mediaCodecInfo.getSupportedTypes(); 116 for (String mimeType : mimeTypes) { 117 if (MediaFormat.MIMETYPE_AUDIO_AAC.equalsIgnoreCase(mimeType)) { 118 MediaCodecInfo.CodecCapabilities caps = mediaCodecInfo.getCapabilitiesForType( 119 mimeType); 120 if (caps.isFormatSupported(format)) { 121 if (!aacDecoderNames.contains(codecName)) { 122 aacDecoderNames.add(codecName); 123 } 124 } 125 break; 126 } 127 } 128 } 129 return aacDecoderNames; 130 } 131 132 /** 133 * Verify the correct decoding of USAC bitstreams with different MPEG-D DRC effect types. 134 */ 135 @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"}) 136 @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION", 137 "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR", 138 "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR", 139 "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL", 140 "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE"}) 141 @Test testDecodeUsacDrcEffectTypeM4a()142 public void testDecodeUsacDrcEffectTypeM4a() throws Exception { 143 Log.v(TAG, "START testDecodeUsacDrcEffectTypeM4a"); 144 145 assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0); 146 147 for (String aacDecName : sAacDecoderNames) { 148 try { 149 runDecodeUsacDrcEffectTypeM4a(aacDecName); 150 } catch (Error err) { 151 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err); 152 } 153 } 154 } 155 runDecodeUsacDrcEffectTypeM4a(String aacDecName)156 private void runDecodeUsacDrcEffectTypeM4a(String aacDecName) throws Exception { 157 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a running for dec=" + aacDecName); 158 // test DRC effectTypeID 1 "NIGHT" 159 // L -3dB -> normalization factor = 1/(10^(-3/10)) = 0.5011f 160 // R +3dB -> normalization factor = 1/(10^( 3/10)) = 1.9952f 161 try { 162 checkUsacDrcEffectType(1, 0.5011f, 1.9952f, "Night", 2, 0, aacDecName); 163 } catch (Exception e) { 164 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/0 failed for dec=" + aacDecName); 165 throw new RuntimeException(e); 166 } 167 168 // test DRC effectTypeID 2 "NOISY" 169 // L +3dB -> normalization factor = 1/(10^( 3/10)) = 1.9952f 170 // R -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f 171 try { 172 checkUsacDrcEffectType(2, 1.9952f, 0.2511f, "Noisy", 2, 0, aacDecName); 173 } catch (Exception e) { 174 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Noisy/2/0 failed for dec=" + aacDecName); 175 throw new RuntimeException(e); 176 } 177 178 // test DRC effectTypeID 3 "LIMITED" 179 // L -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f 180 // R +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f 181 try { 182 checkUsacDrcEffectType(3, 0.2511f, 3.9810f, "Limited", 2, 0, aacDecName); 183 } catch (Exception e) { 184 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/2/0 failed for dec=" 185 + aacDecName); 186 throw new RuntimeException(e); 187 } 188 189 // test DRC effectTypeID 6 "GENERAL" 190 // L +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f 191 // R -3dB -> normalization factor = 1/(10^(-3/10)) = 0.5011f 192 try { 193 checkUsacDrcEffectType(6, 3.9810f, 0.5011f, "General", 2, 0, aacDecName); 194 } catch (Exception e) { 195 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/2/0 failed for dec=" 196 + aacDecName); 197 throw new RuntimeException(e); 198 } 199 200 // test DRC effectTypeID 1 "NIGHT" 201 // L -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f 202 // R +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f 203 // mono -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f 204 try { 205 checkUsacDrcEffectType(1, 0.2511f, 3.9810f, "Night", 2, 1, aacDecName); 206 } catch (Exception e) { 207 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/1 for dec=" + aacDecName); 208 throw new RuntimeException(e); 209 } 210 try { 211 checkUsacDrcEffectType(1, 0.2511f, 0.0f, "Night", 1, 1, aacDecName); 212 } catch (Exception e) { 213 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/1/1 for dec=" + aacDecName); 214 throw new RuntimeException(e); 215 } 216 217 // test DRC effectTypeID 2 "NOISY" 218 // L +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f 219 // R -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f 220 // mono +6dB -> normalization factor = 1/(10^( 6/10)) = 3.9810f 221 try { 222 checkUsacDrcEffectType(2, 3.9810f, 0.1258f, "Noisy", 2, 1, aacDecName); 223 } catch (Exception e) { 224 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Noisy/2/1 for dec=" + aacDecName); 225 throw new RuntimeException(e); 226 } 227 try { 228 checkUsacDrcEffectType(2, 3.9810f, 0.0f, "Noisy", 1, 1, aacDecName); 229 } catch (Exception e) { 230 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Night/2/1 for dec=" + aacDecName); 231 throw new RuntimeException(e); 232 } 233 234 // test DRC effectTypeID 3 "LIMITED" 235 // L -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f 236 // R +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f 237 // mono -9dB -> normalization factor = 1/(10^(-9/10)) = 0.1258f 238 try { 239 checkUsacDrcEffectType(3, 0.1258f, 7.9432f, "Limited", 2, 1, aacDecName); 240 } catch (Exception e) { 241 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/2/1 for dec=" + aacDecName); 242 throw new RuntimeException(e); 243 } 244 try { 245 checkUsacDrcEffectType(3, 0.1258f, 0.0f, "Limited", 1, 1, aacDecName); 246 } catch (Exception e) { 247 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a Limited/1/1 for dec=" + aacDecName); 248 throw new RuntimeException(e); 249 } 250 251 // test DRC effectTypeID 6 "GENERAL" 252 // L +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f 253 // R -6dB -> normalization factor = 1/(10^(-6/10)) = 0.2511f 254 // mono +9dB -> normalization factor = 1/(10^( 9/10)) = 7.9432f 255 try { 256 checkUsacDrcEffectType(6, 7.9432f, 0.2511f, "General", 2, 1, aacDecName); 257 } catch (Exception e) { 258 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/2/1 for dec=" + aacDecName); 259 throw new RuntimeException(e); 260 } 261 try { 262 checkUsacDrcEffectType(6, 7.9432f, 0.0f, "General", 1, 1, aacDecName); 263 } catch (Exception e) { 264 Log.v(TAG, "testDecodeUsacDrcEffectTypeM4a General/1/1 for dec=" + aacDecName); 265 throw new RuntimeException(e); 266 } 267 } 268 269 /** 270 * Verify the correct decoding of USAC bitstreams with album mode. 271 */ 272 @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"}) 273 @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION", 274 "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR", 275 "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR", 276 "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL", 277 "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE", 278 "android.media.MediaFormat#KEY_AAC_DRC_ALBUM_MODE"}) 279 @Test testDecodeUsacDrcAlbumModeM4a()280 public void testDecodeUsacDrcAlbumModeM4a() throws Exception { 281 Log.v(TAG, "START testDecodeUsacDrcAlbumModeM4a"); 282 283 // Album mode is R feature 284 if (!MediaUtils.check(sIsAndroidRAndAbove, "Album mode support requires Android R")) 285 return; 286 287 assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0); 288 289 for (String aacDecName : sAacDecoderNames) { 290 try { 291 runDecodeUsacDrcAlbumModeM4a(aacDecName); 292 } catch (Error err) { 293 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err); 294 } 295 } 296 } 297 runDecodeUsacDrcAlbumModeM4a(String aacDecName)298 private void runDecodeUsacDrcAlbumModeM4a(String aacDecName) throws Exception { 299 // test DRC Album Mode 300 // Track loudness = -19dB 301 // Album Loudness = -21 dB 302 // Fading Gains = -6 dB 303 // Album Mode ON : Gains = -24 - (-21) = -3dB 304 // Album Mode OFF : Gains = (-24 -(-19)) + (-6) = -11 dB 305 try { 306 checkUsacDrcAlbumMode(R.raw.noise_2ch_48khz_tlou_19lufs_alou_21lufs_mp4, aacDecName); 307 } catch (Exception e) { 308 Log.v(TAG, "testDecodeUsacDrcAlbumModeM4a for decoder" + aacDecName); 309 throw new RuntimeException(e); 310 } 311 } 312 313 /** 314 * Verify the correct decoding of USAC bitstreams with config changes. 315 */ 316 @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"}) 317 @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION", 318 "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR", 319 "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR", 320 "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL", 321 "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE"}) 322 @Test testDecodeUsacStreamSwitchingM4a()323 public void testDecodeUsacStreamSwitchingM4a() throws Exception { 324 Log.v(TAG, "START testDecodeUsacStreamSwitchingM4a"); 325 326 assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0); 327 328 for (String aacDecName : sAacDecoderNames) { 329 try { 330 runDecodeUsacStreamSwitchingM4a(aacDecName); 331 } catch (Error err) { 332 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err); 333 } 334 } 335 } 336 runDecodeUsacStreamSwitchingM4a(String aacDecName)337 private void runDecodeUsacStreamSwitchingM4a(String aacDecName) throws Exception { 338 // Stereo 339 // switch between SBR ratios and stereo modes 340 try { 341 checkUsacStreamSwitching(2.5459829E12f, 2, 342 R.raw.noise_2ch_44_1khz_aot42_19_lufs_config_change_mp4, aacDecName); 343 } catch (Exception e) { 344 Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 2ch sbr/stereo switch for " 345 + aacDecName); 346 throw new RuntimeException(e); 347 } 348 349 // Mono 350 // switch between SBR ratios and stereo modes 351 try { 352 checkUsacStreamSwitching(2.24669126E12f, 1, 353 R.raw.noise_1ch_38_4khz_aot42_19_lufs_config_change_mp4, aacDecName); 354 } catch (Exception e) { 355 Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 1ch sbr/stereo switch for " 356 + aacDecName); 357 throw new RuntimeException(e); 358 } 359 360 // Stereo 361 // switch between USAC modes 362 try { 363 checkUsacStreamSwitching(2.1E12f, 2, 364 R.raw.noise_2ch_35_28khz_aot42_19_lufs_drc_config_change_mp4, aacDecName); 365 } catch (Exception e) { 366 Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 2ch USAC mode switch for " 367 + aacDecName); 368 throw new RuntimeException(e); 369 } 370 371 // Mono 372 // switch between USAC modes 373 try { 374 checkUsacStreamSwitching(1.7E12f, 1, 375 R.raw.noise_1ch_29_4khz_aot42_19_lufs_drc_config_change_mp4, aacDecName); 376 } catch (Exception e) { 377 Log.v(TAG, "testDecodeUsacStreamSwitchingM4a failed 1ch USAC mode switch for " 378 + aacDecName); 379 throw new RuntimeException(e); 380 } 381 382 } 383 384 /** 385 * Verify the correct decoding of USAC bitstreams with various sampling rates. 386 */ 387 @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"}) 388 @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION", 389 "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR", 390 "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR", 391 "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL", 392 "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE"}) 393 @Test testDecodeUsacSamplingRatesM4a()394 public void testDecodeUsacSamplingRatesM4a() throws Exception { 395 Log.v(TAG, "START testDecodeUsacSamplingRatesM4a"); 396 397 assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0); 398 399 for (String aacDecName : sAacDecoderNames) { 400 try { 401 runDecodeUsacSamplingRatesM4a(aacDecName); 402 } catch (Error err) { 403 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err); 404 } 405 } 406 } 407 runDecodeUsacSamplingRatesM4a(String aacDecName)408 private void runDecodeUsacSamplingRatesM4a(String aacDecName) throws Exception { 409 try { 410 checkUsacSamplingRate(R.raw.noise_2ch_08khz_aot42_19_lufs_mp4, aacDecName); 411 checkUsacSamplingRate(R.raw.noise_2ch_12khz_aot42_19_lufs_mp4, aacDecName); 412 checkUsacSamplingRate(R.raw.noise_2ch_22_05khz_aot42_19_lufs_mp4, aacDecName); 413 checkUsacSamplingRate(R.raw.noise_2ch_64khz_aot42_19_lufs_mp4, aacDecName); 414 checkUsacSamplingRate(R.raw.noise_2ch_88_2khz_aot42_19_lufs_mp4, aacDecName); 415 checkUsacSamplingRateWoLoudness(R.raw.noise_2ch_19_2khz_aot42_no_ludt_mp4, 416 aacDecName); 417 } catch (Exception e) { 418 Log.v(TAG, "testDecodeUsacSamplingRatesM4a for decoder" + aacDecName); 419 throw new RuntimeException(e); 420 } 421 } 422 423 /** 424 * Verify the correct decoding of USAC bitstreams with different boost and attenuation settings 425 */ 426 @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"}) 427 @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION", 428 "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR", 429 "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR", 430 "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL", 431 "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE", 432 "android.media.MediaFormat#KEY_AAC_DRC_ALBUM_MODE"}) 433 @Test testDecodeUsacDrcBoostAndAttenuationM4a()434 public void testDecodeUsacDrcBoostAndAttenuationM4a() throws Exception { 435 Log.v(TAG, "START testDecodeUsacDrcBoostAndAttenuationM4a"); 436 437 if (!MediaUtils.check(sIsAndroidRAndAbove, "Att/Boost corrected in Android R")) 438 return; 439 440 assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0); 441 442 for (String aacDecName : sAacDecoderNames) { 443 try { 444 runDecodeUsacDrcBoostAndAttenuationM4a(aacDecName); 445 } catch (Error err) { 446 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err); 447 } 448 } 449 } 450 runDecodeUsacDrcBoostAndAttenuationM4a(String aacDecName)451 private void runDecodeUsacDrcBoostAndAttenuationM4a(String aacDecName) throws Exception { 452 Log.v(TAG, "testDecodeUsacDrcBoostAndAttenuationM4a running for dec=" + aacDecName); 453 // test drcBoost and drcAttenuation parameters 454 // DRC effectTypeID 6 "GENERAL" 455 // L +6dB -> normalization factor = 10^(6/10 * (1 - boostFactor:64/127)) = 1.9844f 456 // R -3dB -> normalization factor = 10^(-3/10 * (1 - attenuationFactor:127/127)) = 1.0f 457 try { 458 checkUsacDrcBoostAndAttenuation(1.9844f, 1.0f, 64, 127, 2, aacDecName); 459 } catch (Exception e) { 460 Log.v(TAG, "testDecodeUsacDrcBoostAndAttenuationM4a failed for dec=" + aacDecName); 461 throw new RuntimeException(e); 462 } 463 464 // test drcBoost and drcAttenuation parameters 465 // DRC effectTypeID 6 "GENERAL" 466 // L +6dB -> normalization factor = 10^(6/10 * (1 - boostFactor:127/127)) = 1.0f 467 // R -3dB -> normalization factor = 10^(-3/10 * (1 - attenuationFactor:64/127)) = 0.7099f 468 try { 469 checkUsacDrcBoostAndAttenuation(1.0f, 0.7099f, 127, 64, 2, aacDecName); 470 } catch (Exception e) { 471 Log.v(TAG, "testDecodeUsacDrcBoostAndAttenuationM4a failed for dec=" + aacDecName); 472 throw new RuntimeException(e); 473 } 474 475 // test drcBoost and drcAttenuation parameters 476 // DRC effectTypeID 6 "GENERAL" 477 // L +6dB -> normalization factor = 10^(6/10 * (1 - boostFactor:0/127)) = 3.9811f 478 // R -3dB -> normalization factor = 10^(-3/10 * (1 - attenuationFactor:127/127)) = 1.0f 479 try { 480 checkUsacDrcBoostAndAttenuation(3.9811f, 1.0f, 0, 127, 2, aacDecName); 481 } catch (Exception e) { 482 Log.v(TAG, "testDecodeUsacDrcBoostAndAttenuationM4a failed for dec=" + aacDecName); 483 throw new RuntimeException(e); 484 } 485 486 // test drcBoost and drcAttenuation parameters 487 // DRC effectTypeID 6 "GENERAL" 488 // L +6dB -> normalization factor = 10^(6/10 * (1 - boostFactor:127/127)) = 1.0f 489 // R -3dB -> normalization factor = 10^(-3/10 * (1 - attenuationFactor:0/127)) = 0.5012f 490 try { 491 checkUsacDrcBoostAndAttenuation(1.0f, 0.5012f, 127, 0, 2, aacDecName); 492 } catch (Exception e) { 493 Log.v(TAG, "testDecodeUsacDrcBoostAndAttenuationM4a failed for dec=" + aacDecName); 494 throw new RuntimeException(e); 495 } 496 } 497 498 /** 499 * verify the correct decoding of USAC bitstreams when different kinds of loudness values 500 * are present 501 */ 502 @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"}) 503 @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION", 504 "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR", 505 "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR", 506 "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL", 507 "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE", 508 "android.media.MediaFormat#KEY_AAC_DRC_ALBUM_MODE"}) 509 @Test testDecodeUsacDrcLoudnessPreferenceM4a()510 public void testDecodeUsacDrcLoudnessPreferenceM4a() throws Exception { 511 Log.v(TAG, "START testDecodeUsacDrcLoudnessPreferenceM4a"); 512 513 if (!MediaUtils.check(sIsAndroidRAndAbove, "Loudness preference in Android R")) 514 return; 515 516 assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0); 517 518 for (String aacDecName : sAacDecoderNames) { 519 try { 520 runDecodeUsacDrcLoudnessPreferenceM4a(aacDecName); 521 } catch (Error err) { 522 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err); 523 } 524 } 525 } 526 runDecodeUsacDrcLoudnessPreferenceM4a(String aacDecName)527 private void runDecodeUsacDrcLoudnessPreferenceM4a(String aacDecName) throws Exception { 528 Log.v(TAG, "testDecodeUsacDrcLoudnessPreferenceM4a running for dec=" + aacDecName); 529 // test drc loudness preference 530 // anchor loudness (-17 LUFS) and program loudness (-19 LUFS) are present in one stream 531 // -> anchor loudness should be selected 532 // the bitstream is decoded with targetLoudnessLevel = -16 LUFS and 533 // checked against the energy of the decoded signal without loudness normalization 534 // normfactor = loudness of waveform - targetLoudnessLevel = -1dB = 0.7943 535 try { 536 checkUsacDrcLoudnessPreference( 537 R.raw.noise_2ch_48khz_tlou_19lufs_anchor_17lufs_mp4, 0.7943f, aacDecName); 538 } catch (Exception e) { 539 Log.v(TAG, "testDecodeUsacDrcLoudnessPreferenceM4a failed for dec=" + aacDecName); 540 throw new RuntimeException(e); 541 } 542 543 // test drc loudness preference 544 // expert loudness (-23 LUFS) and program loudness (-19 LUFS) are present in one stream 545 // -> expert loudness should be selected 546 // the bitstream is decoded with targetLoudnessLevel = -16 LUFS and 547 // checked against the energy of the decoded signal without loudness normalization 548 // normfactor = loudness of waveform - targetLoudnessLevel = -7dB = 0.1995 549 try { 550 checkUsacDrcLoudnessPreference( 551 R.raw.noise_2ch_48khz_tlou_19lufs_expert_23lufs_mp4, 0.1995f, aacDecName); 552 } catch (Exception e) { 553 Log.v(TAG, "testDecodeUsacDrcLoudnessPreferenceM4a failed for dec=" + aacDecName); 554 throw new RuntimeException(e); 555 } 556 } 557 558 /** 559 * Verify that the correct output loudness values are returned when decoding USAC bitstreams 560 */ 561 @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"}) 562 @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION", 563 "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR", 564 "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR", 565 "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL", 566 "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE", 567 "android.media.MediaFormat#KEY_AAC_DRC_ALBUM_MODE"}) 568 @Test testDecodeUsacDrcOutputLoudnessM4a()569 public void testDecodeUsacDrcOutputLoudnessM4a() throws Exception { 570 Log.v(TAG, "START testDecodeUsacDrcOutputLoudnessM4a"); 571 572 assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0); 573 574 for (String aacDecName : sAacDecoderNames) { 575 try { 576 runDecodeUsacDrcOutputLoudnessM4a(aacDecName); 577 } catch (Error err) { 578 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err); 579 } 580 } 581 } 582 runDecodeUsacDrcOutputLoudnessM4a(String aacDecName)583 private void runDecodeUsacDrcOutputLoudnessM4a(String aacDecName) throws Exception { 584 Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a running for dec=" + aacDecName); 585 // test drc output loudness 586 // testfile without loudness metadata and loudness normalization off -> expected value: -1 587 try { 588 checkUsacDrcOutputLoudness( 589 R.raw.noise_2ch_19_2khz_aot42_no_ludt_mp4, -1, -1, aacDecName); 590 } catch (Exception e) { 591 Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a failed for dec=" + aacDecName); 592 throw new RuntimeException(e); 593 } 594 595 Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a running for dec=" + aacDecName); 596 // test drc output loudness 597 // testfile without loudness metadata and loudness normalization on 598 // -> expected value: -1 599 try { 600 checkUsacDrcOutputLoudness( 601 R.raw.noise_2ch_19_2khz_aot42_no_ludt_mp4, 64, -1, aacDecName); 602 } catch (Exception e) { 603 Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a failed for dec=" + aacDecName); 604 throw new RuntimeException(e); 605 } 606 607 // test drc output loudness 608 // testfile with MPEG-D DRC loudness metadata and loudness normalization off 609 // -> expected value: loudness metadata in bitstream (-19*-4 = 76) 610 try { 611 checkUsacDrcOutputLoudness( 612 R.raw.noise_2ch_08khz_aot42_19_lufs_mp4, -1, 76, aacDecName); 613 } catch (Exception e) { 614 Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a failed for dec=" + aacDecName); 615 throw new RuntimeException(e); 616 } 617 618 // test drc output loudness 619 // testfile with MPEG-D DRC loudness metadata and loudness normalization off 620 // -> expected value: loudness metadata in bitstream (-22*-4 = 88) 621 try { 622 checkUsacDrcOutputLoudness( 623 R.raw.noise_1ch_38_4khz_aot42_19_lufs_config_change_mp4, -1, 88, aacDecName); 624 } catch (Exception e) { 625 Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a failed for dec=" + aacDecName); 626 throw new RuntimeException(e); 627 } 628 629 // test drc output loudness 630 // testfile with MPEG-D DRC loudness metadata and loudness normalization on 631 // -> expected value: target loudness value (92) 632 try { 633 checkUsacDrcOutputLoudness( 634 R.raw.noise_2ch_08khz_aot42_19_lufs_mp4, 92, 92, aacDecName); 635 } catch (Exception e) { 636 Log.v(TAG, "testDecodeUsacDrcOutputLoudnessM4a failed for dec=" + aacDecName); 637 throw new RuntimeException(e); 638 } 639 } 640 641 642 /** 643 * Verify that seeking works correctly for USAC. 644 * Sync samples have to be taken into consideration. 645 */ 646 @CddTest(requirements = {"5.1.2/C-3-1", "5.1.2/C-3-2"}) 647 @ApiTest(apis = {"android.media.MediaFormat#KEY_AAC_DRC_HEAVY_COMPRESSION", 648 "android.media.MediaFormat#KEY_AAC_DRC_BOOST_FACTOR", 649 "android.media.MediaFormat#KEY_AAC_DRC_ATTENUATION_FACTOR", 650 "android.media.MediaFormat#KEY_AAC_DRC_TARGET_REFERENCE_LEVEL", 651 "android.media.MediaFormat#KEY_AAC_DRC_EFFECT_TYPE", 652 "android.media.MediaFormat#KEY_AAC_DRC_ALBUM_MODE"}) 653 @Test testDecodeUsacSyncSampleSeekingM4a()654 public void testDecodeUsacSyncSampleSeekingM4a() throws Exception { 655 Log.v(TAG, "START testDecodeUsacSyncSampleSeekingM4a"); 656 if(!sIsAndroidRAndAbove) { 657 // The fix for b/158471477 was released in mainline release 300802800 658 // See https://android-build.googleplex.com/builds/treetop/googleplex-android-review/11990700 659 final int MIN_VERSION = 300802800; 660 TestUtils.assumeMainlineModuleAtLeast("com.google.android.media.swcodec", MIN_VERSION); 661 TestUtils.assumeMainlineModuleAtLeast("com.google.android.media", MIN_VERSION); 662 } 663 664 assertTrue("No AAC decoder found", sAacDecoderNames.size() > 0); 665 666 for (String aacDecName : sAacDecoderNames) { 667 try { 668 runDecodeUsacSyncSampleSeekingM4a(aacDecName); 669 } catch (Error err) { 670 throw new Error(err.getMessage() + " [dec=" + aacDecName + "]" , err); 671 } 672 } 673 } 674 runDecodeUsacSyncSampleSeekingM4a(String aacDecName)675 private void runDecodeUsacSyncSampleSeekingM4a(String aacDecName) throws Exception { 676 Log.v(TAG, "testDecodeUsacSyncSampleSeekingM4a running for dec=" + aacDecName); 677 // test usac seeking 678 try { 679 checkUsacSyncSampleSeeking(R.raw.sine_2ch_48khz_aot42_seek_mp4, aacDecName); 680 } catch (Exception e) { 681 Log.v(TAG, "testDecodeUsacSyncSampleSeekingM4a failed for dec=" + aacDecName); 682 throw new RuntimeException(e); 683 } 684 Log.v(TAG, "testDecodeUsacSyncSampleSeekingM4a running for dec=" + aacDecName); 685 } 686 687 /** 688 * Internal utilities 689 */ 690 691 /** 692 * USAC test DRC Effect Type 693 */ checkUsacDrcEffectType(int effectTypeID, float normFactor_L, float normFactor_R, String effectTypeName, int nCh, int aggressiveDrc, String decoderName)694 private void checkUsacDrcEffectType(int effectTypeID, float normFactor_L, float normFactor_R, 695 String effectTypeName, int nCh, int aggressiveDrc, String decoderName) 696 throws Exception { 697 for (boolean runtimeChange : new boolean[] {false, true}) { 698 if (runtimeChange && !sIsAndroidRAndAbove) { 699 // changing decoder configuration after it has been initialized requires R and above 700 continue; 701 } 702 int testinput = -1; 703 AudioParameter decParams = new AudioParameter(); 704 DrcParams drcParams_def = new DrcParams(127, 127, 96, 0, -1); 705 DrcParams drcParams_test = new DrcParams(127, 127, 96, 0, effectTypeID); 706 707 if (aggressiveDrc == 0) { 708 testinput = R.raw.noise_2ch_32khz_aot42_19_lufs_drc_mp4; 709 } else { 710 if (nCh == 2) { 711 testinput = R.raw.noise_2ch_35_28khz_aot42_19_lufs_drc_config_change_mp4; 712 } else if (nCh == 1){ 713 testinput = R.raw.noise_1ch_29_4khz_aot42_19_lufs_drc_config_change_mp4; 714 } 715 } 716 717 short[] decSamples_def = decodeToMemory(decParams, testinput, 718 -1, null, drcParams_def, decoderName); 719 short[] decSamples_test = decodeToMemory(decParams, testinput, 720 -1, null, drcParams_test, decoderName, runtimeChange); 721 722 float[] nrg_def = checkEnergyUSAC(decSamples_def, decParams, nCh, 1, 0); 723 float[] nrg_test = checkEnergyUSAC(decSamples_test, decParams, nCh, 1, 1); 724 725 if (nCh == 2) { 726 float nrgRatio_L = (nrg_test[1]/nrg_def[1])/normFactor_L; 727 float nrgRatio_R = (nrg_test[2]/nrg_def[2])/normFactor_R; 728 if ((nrgRatio_R > 1.05f || nrgRatio_R < 0.95f) 729 || (nrgRatio_L > 1.05f || nrgRatio_L < 0.95f) ){ 730 throw new Exception("DRC Effect Type '" + effectTypeName + "' not as expected"); 731 } 732 } else if (nCh == 1){ 733 float nrgRatio_L = (nrg_test[0]/nrg_def[0])/normFactor_L; 734 if (nrgRatio_L > 1.05f || nrgRatio_L < 0.95f){ 735 throw new Exception("DRC Effect Type '" + effectTypeName + "' not as expected"); 736 } 737 } 738 } 739 } 740 741 /** 742 * USAC test stream switching 743 */ checkUsacStreamSwitching(float nrg_ref, int encNch, int testinput, String decoderName)744 private void checkUsacStreamSwitching(float nrg_ref, int encNch, int testinput, 745 String decoderName) throws Exception 746 { 747 AudioParameter decParams = new AudioParameter(); 748 DrcParams drcParams = new DrcParams(127, 127, 64, 0, -1); 749 750 // Check stereo stream switching 751 short[] decSamples = decodeToMemory(decParams, testinput, 752 -1, null, drcParams, decoderName); 753 float[] nrg = checkEnergyUSAC(decSamples, decParams, encNch, 1); 754 755 float nrgRatio = nrg[0] / nrg_ref; 756 757 // Check if energy levels are within 15% of the reference 758 // Energy drops within the decoded stream are checked by checkEnergyUSAC() within every 759 // 250ms interval 760 if (nrgRatio > 1.15f || nrgRatio < 0.85f ) { 761 throw new Exception("Config switching not as expected"); 762 } 763 } 764 765 /** 766 * USAC test sampling rate 767 */ checkUsacSamplingRate(int testinput, String decoderName)768 private void checkUsacSamplingRate(int testinput, String decoderName) throws Exception { 769 AudioParameter decParams = new AudioParameter(); 770 DrcParams drcParams_def = new DrcParams(127, 127, 64, 0, -1); 771 DrcParams drcParams_test = new DrcParams(127, 127, 96, 0, -1); 772 773 short[] decSamples_def = decodeToMemory(decParams, testinput, 774 -1, null, drcParams_def, decoderName); 775 short[] decSamples_test = decodeToMemory(decParams, testinput, 776 -1, null, drcParams_test, decoderName); 777 778 float[] nrg_def = checkEnergyUSAC(decSamples_def, decParams, 2, 1); 779 float[] nrg_test = checkEnergyUSAC(decSamples_test, decParams, 2, 1); 780 781 float nrgRatio = nrg_def[0]/nrg_test[0]; 782 783 // normFactor = 1/(10^(-8/10)) = 6.3f 784 nrgRatio = nrgRatio / 6.3f; 785 786 // Check whether behavior is as expected 787 if (nrgRatio > 1.05f || nrgRatio < 0.95f ){ 788 throw new Exception("Sampling rate not supported"); 789 } 790 } 791 792 /** 793 * USAC test sampling rate for streams without loudness application 794 */ checkUsacSamplingRateWoLoudness(int testinput, String decoderName)795 private void checkUsacSamplingRateWoLoudness(int testinput, String decoderName) throws Exception 796 { 797 AudioParameter decParams = new AudioParameter(); 798 DrcParams drcParams = new DrcParams(); 799 800 short[] decSamples = decodeToMemory(decParams, testinput, -1, null, drcParams, decoderName); 801 802 float[] nrg = checkEnergyUSAC(decSamples, decParams, 2, 1); 803 804 float nrg_ref = 3.15766394E12f; 805 float nrgRatio = nrg_ref/nrg[0]; 806 807 // Check whether behavior is as expected 808 if (nrgRatio > 1.05f || nrgRatio < 0.95f ){ 809 throw new Exception("Sampling rate not supported"); 810 } 811 } 812 813 /** 814 * USAC test DRC Album Mode 815 */ checkUsacDrcAlbumMode(int testinput, String decoderName)816 private void checkUsacDrcAlbumMode(int testinput, String decoderName) throws Exception { 817 for (boolean runtimeChange : new boolean[] {false, true}) { 818 AudioParameter decParams = new AudioParameter(); 819 DrcParams drcParams_album_off = new DrcParams(127, 127, 64, 0, 0, 0); 820 DrcParams drcParams_album_on = new DrcParams(127, 127, 64, 0, 0, 1); 821 822 short[] decSamples_album_off = decodeToMemory( 823 decParams, testinput, -1, null, drcParams_album_off, decoderName); 824 short[] decSamples_album_on = decodeToMemory( 825 decParams, testinput, -1, null, drcParams_album_on, decoderName, runtimeChange); 826 827 float[] nrg_album_off = checkEnergyUSAC(decSamples_album_off, decParams, 2, 1); 828 float[] nrg_album_on = checkEnergyUSAC(decSamples_album_on, decParams, 2, 1); 829 830 float normFactor = 6.3095f; 831 832 float nrgRatio = (nrg_album_on[0]/nrg_album_off[0])/normFactor; 833 float nrgRatio_L = (nrg_album_on[1]/nrg_album_off[1])/normFactor; 834 float nrgRatio_R = (nrg_album_on[2]/nrg_album_off[2])/normFactor; 835 836 if (nrgRatio > 1.05f || nrgRatio < 0.95f ){ 837 throw new Exception("DRC Album Mode not supported, energy ratio " + nrgRatio); 838 } 839 } 840 } 841 842 /** 843 * USAC test DRC Boost and Attenuation 844 */ checkUsacDrcBoostAndAttenuation(float normFactor_L, float normFactor_R, int boostFactor, int attenuationFactor, int nCh, String decoderName)845 private void checkUsacDrcBoostAndAttenuation(float normFactor_L, float normFactor_R, 846 int boostFactor, int attenuationFactor, 847 int nCh, String decoderName) throws Exception { 848 for (boolean runtimeChange : new boolean[] {false, true}) { 849 if (runtimeChange && !sIsAndroidRAndAbove) { 850 // changing decoder configuration after it has been initialized requires R and above 851 continue; 852 } 853 854 int testinput = R.raw.noise_2ch_32khz_aot42_19_lufs_drc_mp4; 855 856 AudioParameter decParams = new AudioParameter(); 857 DrcParams drcParams_def = new DrcParams(127, 127, 64, 0, 6); 858 DrcParams drcParams_test = new DrcParams(boostFactor, attenuationFactor, 64, 0, 6); 859 860 short[] decSamples_def = decodeToMemory(decParams, testinput, -1, null, 861 drcParams_def, decoderName); 862 short[] decSamples_test = decodeToMemory(decParams, testinput, -1, null, 863 drcParams_test, decoderName, runtimeChange); 864 865 float[] nrg_def = checkEnergyUSAC(decSamples_def, decParams, 2, 1); 866 float[] nrg_test = checkEnergyUSAC(decSamples_test, decParams, 2, 1); 867 868 float nrgRatioLeft = nrg_test[1] / nrg_def[1]; 869 float nrgRatioRight = nrg_test[2] / nrg_def[2]; 870 871 float testValueLeft = normFactor_L * nrgRatioLeft; 872 float testValueRight = normFactor_R * nrgRatioRight; 873 874 // Check whether loudness behavior is as expected 875 if (testValueLeft > 1.05f || testValueLeft < 0.95f) { 876 throw new Exception("DRC boost/attenuation behavior not as expected"); 877 } 878 if (testValueRight > 1.05f || testValueRight < 0.95f) { 879 throw new Exception("DRC boost/attenuation behavior not as expected"); 880 } 881 } 882 } 883 884 /** 885 * USAC test Loudness Preference 886 */ checkUsacDrcLoudnessPreference(int testInput, float normFactor, String decoderName)887 private void checkUsacDrcLoudnessPreference(int testInput, float normFactor, String decoderName) throws Exception { 888 889 AudioParameter decParams = new AudioParameter(); 890 DrcParams drcParams_def = new DrcParams(127, 127, -1, 0, 6); 891 DrcParams drcParams_test = new DrcParams(127, 127, 64, 0, 6); 892 893 // Check drc loudness preference 894 short[] decSamples_def = decodeToMemory(decParams, testInput, -1, null, drcParams_def, decoderName); 895 short[] decSamples_test = decodeToMemory(decParams, testInput, -1, null, drcParams_test, decoderName); 896 897 float[] nrg_def = checkEnergyUSAC(decSamples_def, decParams, 2, 1); 898 float[] nrg_test = checkEnergyUSAC(decSamples_test, decParams, 2, 1); 899 900 float nrgRatio = (nrg_test[0]/nrg_def[0]); 901 nrgRatio = nrgRatio * normFactor; 902 903 if (nrgRatio > 1.05f || nrgRatio < 0.95f ){ 904 throw new Exception("DRC Loudness preference not as expected"); 905 } 906 } 907 908 /** 909 * USAC test Output Loudness 910 */ checkUsacDrcOutputLoudness(int testInput, int decoderTargetLevel, int expectedOutputLoudness, String decoderName)911 private void checkUsacDrcOutputLoudness(int testInput, int decoderTargetLevel, 912 int expectedOutputLoudness, String decoderName) throws Exception { 913 for (boolean runtimeChange : new boolean[] {false, true}) { 914 AudioParameter decParams = new AudioParameter(); 915 DrcParams drcParams_test = new DrcParams(127, 127, decoderTargetLevel, 0, 6); 916 917 // Check drc loudness preference 918 short[] decSamples_test = decodeToMemory( 919 decParams, testInput, -1, null, drcParams_test, 920 decoderName, runtimeChange, expectedOutputLoudness); 921 } 922 } 923 checkUsacSyncSampleSeeking(int testInput, String decoderName)924 private void checkUsacSyncSampleSeeking(int testInput, String decoderName) throws Exception { 925 926 AudioParameter decParams = new AudioParameter(); 927 DrcParams drcParams_def = new DrcParams(); 928 929 short[] decSamples_seek_next_sync = decodeToMemory(decParams, testInput, -1, null, 930 drcParams_def, decoderName, false, -2, true, 1100000, 931 MediaExtractor.SEEK_TO_NEXT_SYNC); 932 float[] nrg_seek_next_sync = checkEnergyUSAC(decSamples_seek_next_sync, decParams, 2, 1); 933 } 934 935 /** 936 * Perform a segmented energy analysis on given audio signal samples and run several tests on 937 * the energy values. 938 * 939 * The main purpose is to verify whether a USAC decoder implementation applies Spectral Band 940 * Replication (SBR), Parametric Stereo (PS) and Dynamic Range Control (DRC) correctly. All 941 * tools are inherent parts to either the MPEG-D USAC audio codec or the MPEG-D DRC tool. 942 * 943 * In addition, this test can verify the correct decoding of multi-channel (e.g. 5.1 channel) 944 * streams or the creation of a downmixed signal. 945 * 946 * Note: This test procedure is not an MPEG Conformance Test and can not serve as a replacement. 947 * 948 * @param decSamples the decoded audio samples to be tested 949 * @param decParams the audio parameters of the given audio samples (decSamples) 950 * @param encNch the encoded number of audio channels (number of channels of the original 951 * input) 952 * @param drcContext indicate to use test criteria applicable for DRC testing 953 * @return array of energies, at index 0: accumulated energy of all channels, and 954 * index 1 and over contain the individual channel energies 955 * @throws RuntimeException 956 */ checkEnergyUSAC(short[] decSamples, AudioParameter decParams, int encNch, int drcContext)957 protected float[] checkEnergyUSAC(short[] decSamples, AudioParameter decParams, 958 int encNch, int drcContext) 959 { 960 final float[] nrg = checkEnergyUSAC(decSamples, decParams, encNch, drcContext, 0); 961 return nrg; 962 } 963 964 /** 965 * Same as {@link #checkEnergyUSAC(short[], AudioParameter, int, int)} but with DRC effect type 966 * @param decSamples 967 * @param decParams 968 * @param encNch 969 * @param drcContext 970 * @param drcApplied indicate if MPEG-D DRC Effect Type has been applied 971 * @return 972 * @throws RuntimeException 973 */ checkEnergyUSAC(short[] decSamples, AudioParameter decParams, int encNch, int drcContext, int drcApplied)974 private float[] checkEnergyUSAC(short[] decSamples, AudioParameter decParams, 975 int encNch, int drcContext, int drcApplied) 976 throws RuntimeException 977 { 978 String localTag = TAG + "#checkEnergyUSAC"; 979 980 // the number of segments per block 981 final int nSegPerBlk = 4; 982 // the number of input channels 983 final int nCh = encNch; 984 // length of one (LB/HB) block [samples] 985 final int nBlkSmp = decParams.getSamplingRate(); 986 // length of one segment [samples] 987 final int nSegSmp = nBlkSmp / nSegPerBlk; 988 // actual # samples per channel (total) 989 final int smplPerChan = decSamples.length / nCh; 990 // actual # samples per segment (all ch) 991 final int nSegSmpTot = nSegSmp * nCh; 992 // signal offset between chans [segments] 993 final int nSegChOffst = 2 * nSegPerBlk; 994 // // the number of channels to be analyzed 995 final int procNch = Math.min(nCh, encNch); 996 // all original configs with more than five channel have an LFE 997 final int encEffNch = (encNch > 5) ? encNch-1 : encNch; 998 // expected number of decoded audio samples 999 final int expSmplPerChan = Math.max(encEffNch, 2) * nSegChOffst * nSegSmp; 1000 // flag telling that input is dmx signal 1001 final boolean isDmx = nCh < encNch; 1002 final float nrgRatioThresh = 0.0f; 1003 // the num analyzed channels with signal 1004 int effProcNch = procNch; 1005 1006 // get the signal offset by counting zero samples at the very beginning (over all channels) 1007 // sample value threshold 4 signal search 1008 final int zeroSigThresh = 1; 1009 // receives the number of samples that are in front of the actual signal 1010 int signalStart = smplPerChan; 1011 // receives the number of null samples (per chan) at the very beginning 1012 int noiseStart = signalStart; 1013 1014 for (int smpl = 0; smpl < decSamples.length; smpl++) { 1015 int value = Math.abs(decSamples[smpl]); 1016 1017 if (value > 0 && noiseStart == signalStart) { 1018 // store start of prepended noise (can be same as signalStart) 1019 noiseStart = smpl / nCh; 1020 } 1021 1022 if (value > zeroSigThresh) { 1023 // store signal start offset [samples] 1024 signalStart = smpl / nCh; 1025 break; 1026 } 1027 } 1028 1029 signalStart = (signalStart > noiseStart+1) ? signalStart : noiseStart; 1030 1031 // check if the decoder reproduced a waveform or kept silent 1032 assertTrue ("no signal found in any channel!", signalStart < smplPerChan); 1033 1034 // max num seg that fit into signal 1035 final int totSeg = (smplPerChan - signalStart) / nSegSmp; 1036 // max num relevant samples (per channel) 1037 final int totSmp = nSegSmp * totSeg; 1038 1039 // check if the number of reproduced segments in the audio file is valid 1040 assertTrue("no segments left to test after signal search", totSeg > 0); 1041 1042 // get the energies and the channel offsets by searching for the first segment above the 1043 // energy threshold: 1044 // ratio of zeroNrgThresh to the max nrg 1045 final double zeroMaxNrgRatio = 0.001f; 1046 // threshold to classify segment energies 1047 double zeroNrgThresh = nSegSmp * nSegSmp; 1048 // will store the max seg nrg over all ch 1049 double totMaxNrg = 0.0f; 1050 // array receiving the segment energies 1051 double[][] nrg = new double[procNch][totSeg]; 1052 // array for channel offsets 1053 int[] offset = new int[procNch]; 1054 // array receiving the segment energy status over all channels 1055 boolean[] sigSeg = new boolean[totSeg]; 1056 // energy per channel 1057 double[] nrgPerChannel = new double[procNch]; 1058 // return value: [0]: total energy of all channels 1059 // [1 ... procNch + 1]: energy of the individual channels 1060 float[] nrgTotal = new float[procNch + 1]; 1061 // mapping array to sort channels 1062 int[] chMap = new int[nCh]; 1063 1064 // calculate the segmental energy for each channel 1065 for (int ch = 0; ch < procNch; ch++) { 1066 offset[ch] = -1; 1067 1068 for (int seg = 0; seg < totSeg; seg++) { 1069 final int smpStart = (signalStart * nCh) + (seg * nSegSmpTot) + ch; 1070 final int smpStop = smpStart + nSegSmpTot; 1071 1072 for (int smpl = smpStart; smpl < smpStop; smpl += nCh) { 1073 // accumulate total energy per channel 1074 nrgPerChannel[ch] += decSamples[smpl] * decSamples[smpl]; 1075 // accumulate segment energy 1076 nrg[ch][seg] += nrgPerChannel[ch]; 1077 } 1078 1079 // store 1st segment (index) per channel which has energy above the threshold to get 1080 // the ch offsets 1081 if (nrg[ch][seg] > zeroNrgThresh && offset[ch] < 0) { 1082 offset[ch] = seg / nSegChOffst; 1083 } 1084 1085 // store the max segment nrg over all ch 1086 if (nrg[ch][seg] > totMaxNrg) { 1087 totMaxNrg = nrg[ch][seg]; 1088 } 1089 1090 // store whether the channel has energy in this segment 1091 sigSeg[seg] |= nrg[ch][seg] > zeroNrgThresh; 1092 } 1093 1094 // if one channel has no signal it is most probably the LFE the LFE is no 1095 // effective channel 1096 if (offset[ch] < 0) { 1097 effProcNch -= 1; 1098 offset[ch] = effProcNch; 1099 } 1100 1101 // recalculate the zero signal threshold based on the 1st channels max energy for 1102 // all subsequent checks 1103 if (ch == 0) { 1104 zeroNrgThresh = zeroMaxNrgRatio * totMaxNrg; 1105 } 1106 } 1107 1108 // check if the LFE is decoded properly 1109 assertTrue("more than one LFE detected", effProcNch >= procNch - 1); 1110 1111 // check if the amount of samples is valid 1112 assertTrue(String.format("less samples decoded than expected: %d < %d", 1113 decSamples.length - (signalStart * nCh), 1114 totSmp * effProcNch), 1115 decSamples.length - (signalStart * nCh) >= totSmp * effProcNch); 1116 1117 // for multi-channel signals the only valid front channel orders 1118 // are L, R, C or C, L, R (L=left, R=right, C=center) 1119 if (procNch >= 5) { 1120 final int[] frontChMap1 = {2, 0, 1}; 1121 final int[] frontChMap2 = {0, 1, 2}; 1122 1123 // check if the channel mapping is valid 1124 if (!(Arrays.equals(Arrays.copyOfRange(offset, 0, 3), frontChMap1) 1125 || Arrays.equals(Arrays.copyOfRange(offset, 0, 3), frontChMap2))) { 1126 fail("wrong front channel mapping"); 1127 } 1128 } 1129 1130 // create mapping table to address channels from front to back the LFE must be last 1131 if (drcContext == 0) { 1132 // check whether every channel occurs exactly once 1133 for (int ch = 0; ch < effProcNch; ch++) { 1134 int occurred = 0; 1135 1136 for (int idx = 0; idx < procNch; idx++) { 1137 if (offset[idx] == ch) { 1138 occurred += 1; 1139 chMap[ch] = idx; 1140 } 1141 } 1142 1143 // check if one channel is mapped more than one time 1144 assertTrue(String.format("channel %d occurs %d times in the mapping", ch, occurred), 1145 occurred == 1); 1146 } 1147 } else { 1148 for (int ch = 0; ch < procNch; ch++) { 1149 chMap[ch] = ch; 1150 } 1151 } 1152 1153 // reference min energy for the 1st ch; others will be compared against 1st 1154 double refMinNrg = zeroNrgThresh; 1155 1156 // calculate total energy, min and max energy 1157 for (int ch = 0; ch < procNch; ch++) { 1158 // resolve channel mapping 1159 int idx = chMap[ch]; 1160 // signal offset [segments] 1161 final int ofst = offset[idx] * nSegChOffst; 1162 1163 if (ch <= effProcNch && ofst < totSeg) { 1164 // the last segment that has energy 1165 int nrgSegEnd; 1166 // the number of segments with energy 1167 int nrgSeg; 1168 1169 if (drcContext == 0) { 1170 1171 // the first channel of a mono or stereo signal has full signal all others have 1172 // one LB + one HB block 1173 if ((encNch <= 2) && (ch == 0)) { 1174 nrgSeg = totSeg; 1175 } else { 1176 nrgSeg = Math.min(totSeg, (2 * nSegPerBlk) + ofst) - ofst; 1177 } 1178 } else { 1179 nrgSeg = totSeg; 1180 } 1181 1182 nrgSegEnd = ofst + nrgSeg; 1183 1184 // find min and max energy of all segments that should have signal 1185 double minNrg = nrg[idx][ofst]; // channels minimum segment energy 1186 double maxNrg = nrg[idx][ofst]; // channels maximum segment energy 1187 1188 // values of 1st segment already assigned 1189 for (int seg = ofst + 1; seg < nrgSegEnd; seg++) { 1190 if (nrg[idx][seg] < minNrg) { 1191 minNrg = nrg[idx][seg]; 1192 } 1193 1194 if (nrg[idx][seg] > maxNrg) { 1195 maxNrg = nrg[idx][seg]; 1196 } 1197 } 1198 1199 // check if the energy of this channel is > 0 1200 assertTrue(String.format("max energy of channel %d is zero", ch),maxNrg > 0.0f); 1201 1202 if (drcContext == 0) { 1203 // check the channels minimum energy >= refMinNrg 1204 assertTrue(String.format("channel %d has not enough energy", ch), 1205 minNrg >= refMinNrg); 1206 1207 if (ch == 0) { 1208 // use 85% of 1st channels min energy as reference the other chs must meet 1209 refMinNrg = minNrg * 0.85f; 1210 } else if (isDmx && (ch == 1)) { 1211 // in case of downmixed signal the energy can be lower depending on the 1212 refMinNrg *= 0.50f; 1213 } 1214 1215 // calculate and check the energy ratio 1216 final double nrgRatio = minNrg / maxNrg; 1217 1218 // check if the threshold is exceeded 1219 assertTrue(String.format("energy ratio of channel %d below threshold", ch), 1220 nrgRatio >= nrgRatioThresh); 1221 1222 if (!isDmx) { 1223 if (nrgSegEnd < totSeg) { 1224 // consider that some noise can extend into the subsequent segment 1225 // allow this to be at max 20% of the channels minimum energy 1226 assertTrue( 1227 String.format("min energy after noise above threshold (%.2f)", 1228 nrg[idx][nrgSegEnd]), 1229 nrg[idx][nrgSegEnd] < minNrg * 0.20f); 1230 nrgSegEnd += 1; 1231 } 1232 } else { 1233 // ignore all subsequent segments in case of a downmixed signal 1234 nrgSegEnd = totSeg; 1235 } 1236 1237 // zero-out the verified energies to simplify the subsequent check 1238 for (int seg = ofst; seg < nrgSegEnd; seg++) { 1239 nrg[idx][seg] = 0.0f; 1240 } 1241 1242 // check zero signal parts 1243 for (int seg = 0; seg < totSeg; seg++) { 1244 assertTrue(String.format("segment %d in channel %d has signal where should " 1245 + "be none (%.2f)", seg, ch, nrg[idx][seg]), 1246 nrg[idx][seg] < zeroNrgThresh); 1247 } 1248 } 1249 } 1250 1251 // test whether each segment has energy in at least one channel 1252 for (int seg = 0; seg < totSeg; seg++) { 1253 assertTrue(String.format("no channel has energy in segment %d", seg), sigSeg[seg]); 1254 } 1255 1256 nrgTotal[0] += (float)nrgPerChannel[ch]; 1257 nrgTotal[ch + 1] = (float)nrgPerChannel[ch]; 1258 } 1259 1260 float errorMargin = 0.0f; 1261 if (drcApplied == 0) { 1262 errorMargin = 0.25f; 1263 } else if (drcApplied == 1) { 1264 errorMargin = 0.40f; 1265 } 1266 1267 float totSegEnergy = 0.0f; 1268 float[] segEnergy = new float[totSeg]; 1269 for (int seg = totSeg - 1; seg >= 0; seg--) { 1270 if (seg != 0) { 1271 for (int ch = 0; ch < nCh; ch++) { 1272 segEnergy[seg] += nrg[ch][seg] - nrg[ch][seg - 1]; 1273 } 1274 totSegEnergy += segEnergy[seg]; 1275 } else { 1276 for (int ch = 0; ch < nCh; ch++) { 1277 segEnergy[seg] += nrg[ch][seg]; 1278 } 1279 } 1280 } 1281 float avgSegEnergy = totSegEnergy / (totSeg - 1); 1282 for (int seg = 1; seg < totSeg; seg++) { 1283 float energyRatio = segEnergy[seg] / avgSegEnergy; 1284 if ((energyRatio > (1.0f + errorMargin) ) || (energyRatio < (1.0f - errorMargin) )) { 1285 fail("Energy drop out"); 1286 } 1287 } 1288 1289 // return nrgTotal: [0]: accumulated energy of all channels, [1 ... ] channel energies 1290 return nrgTotal; 1291 } 1292 1293 /** 1294 * Decodes a compressed bitstream in the ISOBMFF into the RAM of the device. 1295 * 1296 * The decoder decodes compressed audio data as stored in the ISO Base Media File Format 1297 * (ISOBMFF) aka .mp4/.m4a. The decoder is not reproducing the waveform but stores the decoded 1298 * samples in the RAM of the device under test. 1299 * 1300 * @param audioParams the decoder parameter configuration 1301 * @param testinput the compressed audio stream 1302 * @param eossample the End-Of-Stream indicator 1303 * @param timestamps the time stamps to decode 1304 * @param drcParams the MPEG-D DRC decoder parameter configuration 1305 * @param decoderName if non null, the name of the decoder to use for the decoding, otherwise 1306 * the default decoder for the format will be used 1307 * @param runtimeChange defines whether the decoder is configured at runtime or configured 1308 * before starting to decode 1309 * @param expectedOutputLoudness value to check if the correct output loudness is returned 1310 * by the decoder 1311 * @param seek_enable defines whether there will be an initial seek 1312 * @param seek_duration seeking duration in microseconds 1313 * @param seek_mode seeking mode 1314 * 1315 * @throws RuntimeException 1316 */ 1317 public short[] decodeToMemory(AudioParameter audioParams, int testinput, int eossample, 1318 List<Long> timestamps, DrcParams drcParams, String decoderName, boolean runtimeChange, 1319 int expectedOutputLoudness, 1320 boolean seek_enable, int seek_duration, int seek_mode) throws IOException { 1321 // TODO: code is the same as in DecoderTest, differences are: 1322 // - addition of application of DRC parameters 1323 // - no need/use of resetMode, configMode 1324 // Split method so code can be shared 1325 1326 final String localTag = TAG + "#decodeToMemory"; 1327 short [] decoded = new short[0]; 1328 int decodedIdx = 0; 1329 1330 AssetFileDescriptor testFd = mResources.openRawResourceFd(testinput); 1331 1332 MediaExtractor extractor; 1333 MediaCodec codec; 1334 ByteBuffer[] codecInputBuffers; 1335 ByteBuffer[] codecOutputBuffers; 1336 1337 extractor = new MediaExtractor(); 1338 extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(), 1339 testFd.getLength()); 1340 testFd.close(); 1341 1342 assertEquals("wrong number of tracks", 1, extractor.getTrackCount()); 1343 MediaFormat format = extractor.getTrackFormat(0); 1344 String mime = format.getString(MediaFormat.KEY_MIME); 1345 assertTrue("not an audio file", mime.startsWith("audio/")); 1346 1347 MediaFormat configFormat = format; 1348 if (decoderName == null) { 1349 codec = MediaCodec.createDecoderByType(mime); 1350 } else { 1351 codec = MediaCodec.createByCodecName(decoderName); 1352 } 1353 1354 // set DRC parameters 1355 if (drcParams != null) { 1356 configFormat.setInteger(MediaFormat.KEY_AAC_DRC_HEAVY_COMPRESSION, drcParams.mHeavy); 1357 if (!runtimeChange) { 1358 configFormat.setInteger(MediaFormat.KEY_AAC_DRC_BOOST_FACTOR, drcParams.mBoost); 1359 configFormat.setInteger(MediaFormat.KEY_AAC_DRC_ATTENUATION_FACTOR, drcParams.mCut); 1360 if (drcParams.mDecoderTargetLevel != 0) { 1361 configFormat.setInteger(MediaFormat.KEY_AAC_DRC_TARGET_REFERENCE_LEVEL, 1362 drcParams.mDecoderTargetLevel); 1363 } 1364 if (drcParams.mEffectType != 0){ 1365 configFormat.setInteger(MediaFormat.KEY_AAC_DRC_EFFECT_TYPE, 1366 drcParams.mEffectType); 1367 } 1368 if (drcParams.mAlbumMode != 0) { 1369 configFormat.setInteger(MediaFormat.KEY_AAC_DRC_ALBUM_MODE, 1370 drcParams.mAlbumMode); 1371 } 1372 } 1373 } 1374 1375 Log.v(localTag, "configuring with " + configFormat); 1376 codec.configure(configFormat, null /* surface */, null /* crypto */, 0 /* flags */); 1377 1378 if (drcParams != null && sIsAndroidRAndAbove) { // querying output format requires R 1379 if(!runtimeChange) { 1380 if (drcParams.mAlbumMode != 0) { 1381 int albumModeFromCodec = DecoderTest.getOutputFormatInteger(codec, 1382 MediaFormat.KEY_AAC_DRC_ALBUM_MODE); 1383 if (albumModeFromCodec != drcParams.mAlbumMode) { 1384 fail("Drc AlbumMode received from MediaCodec is not the Album Mode set"); 1385 } 1386 } 1387 if (drcParams.mEffectType != 0) { 1388 final int effectTypeFromCodec = DecoderTest.getOutputFormatInteger(codec, 1389 MediaFormat.KEY_AAC_DRC_EFFECT_TYPE); 1390 if (effectTypeFromCodec != drcParams.mEffectType) { 1391 fail("Drc Effect Type received from MediaCodec is not the Effect Type set"); 1392 } 1393 } 1394 if (drcParams.mDecoderTargetLevel != 0) { 1395 final int targetLevelFromCodec = DecoderTest.getOutputFormatInteger(codec, 1396 MediaFormat.KEY_AAC_DRC_TARGET_REFERENCE_LEVEL); 1397 if (targetLevelFromCodec != drcParams.mDecoderTargetLevel) { 1398 fail("Drc Target Reference Level received from MediaCodec is not the Target Reference Level set"); 1399 } 1400 } 1401 } 1402 } 1403 1404 codec.start(); 1405 codecInputBuffers = codec.getInputBuffers(); 1406 codecOutputBuffers = codec.getOutputBuffers(); 1407 1408 if (drcParams != null) { 1409 if (runtimeChange) { 1410 Bundle b = new Bundle(); 1411 b.putInt(MediaFormat.KEY_AAC_DRC_BOOST_FACTOR, drcParams.mBoost); 1412 b.putInt(MediaFormat.KEY_AAC_DRC_ATTENUATION_FACTOR, drcParams.mCut); 1413 if (drcParams.mEffectType != 0) { 1414 b.putInt(MediaFormat.KEY_AAC_DRC_EFFECT_TYPE, drcParams.mEffectType); 1415 } 1416 if (drcParams.mDecoderTargetLevel != 0) { 1417 b.putInt(MediaFormat.KEY_AAC_DRC_TARGET_REFERENCE_LEVEL, 1418 drcParams.mDecoderTargetLevel); 1419 } 1420 if (drcParams.mAlbumMode != 0) { 1421 b.putInt(MediaFormat.KEY_AAC_DRC_ALBUM_MODE, drcParams.mAlbumMode); 1422 } 1423 codec.setParameters(b); 1424 } 1425 } 1426 1427 extractor.selectTrack(0); 1428 1429 // execute initial seeking if specified 1430 if (seek_enable) { 1431 codec.flush(); 1432 extractor.seekTo(seek_duration, seek_mode); 1433 } 1434 1435 // start decoding 1436 final long kTimeOutUs = 5000; 1437 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); 1438 boolean sawInputEOS = false; 1439 boolean sawOutputEOS = false; 1440 int noOutputCounter = 0; 1441 int samplecounter = 0; 1442 1443 // main decoding loop 1444 while (!sawOutputEOS && noOutputCounter < 50) { 1445 noOutputCounter++; 1446 if (!sawInputEOS) { 1447 int inputBufIndex = codec.dequeueInputBuffer(kTimeOutUs); 1448 1449 if (inputBufIndex >= 0) { 1450 ByteBuffer dstBuf = codecInputBuffers[inputBufIndex]; 1451 1452 int sampleSize = 1453 extractor.readSampleData(dstBuf, 0 /* offset */); 1454 1455 long presentationTimeUs = 0; 1456 1457 if (sampleSize < 0 && eossample > 0) { 1458 fail("test is broken: never reached eos sample"); 1459 } 1460 1461 if (sampleSize < 0) { 1462 Log.d(TAG, "saw input EOS."); 1463 sawInputEOS = true; 1464 sampleSize = 0; 1465 } else { 1466 if (samplecounter == eossample) { 1467 sawInputEOS = true; 1468 } 1469 samplecounter++; 1470 presentationTimeUs = extractor.getSampleTime(); 1471 } 1472 1473 codec.queueInputBuffer( 1474 inputBufIndex, 1475 0 /* offset */, 1476 sampleSize, 1477 presentationTimeUs, 1478 sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0); 1479 1480 if (!sawInputEOS) { 1481 extractor.advance(); 1482 } 1483 } 1484 } 1485 1486 int res = codec.dequeueOutputBuffer(info, kTimeOutUs); 1487 1488 if (res >= 0) { 1489 //Log.d(TAG, "got frame, size " + info.size + "/" + info.presentationTimeUs); 1490 1491 if (info.size > 0) { 1492 noOutputCounter = 0; 1493 if (timestamps != null) { 1494 timestamps.add(info.presentationTimeUs); 1495 } 1496 } 1497 1498 int outputBufIndex = res; 1499 ByteBuffer buf = codecOutputBuffers[outputBufIndex]; 1500 1501 if (decodedIdx + (info.size / 2) >= decoded.length) { 1502 decoded = Arrays.copyOf(decoded, decodedIdx + (info.size / 2)); 1503 } 1504 1505 buf.position(info.offset); 1506 for (int i = 0; i < info.size; i += 2) { 1507 decoded[decodedIdx++] = buf.getShort(); 1508 } 1509 1510 codec.releaseOutputBuffer(outputBufIndex, false /* render */); 1511 1512 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { 1513 Log.d(TAG, "saw output EOS."); 1514 sawOutputEOS = true; 1515 } 1516 } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 1517 codecOutputBuffers = codec.getOutputBuffers(); 1518 1519 Log.d(TAG, "output buffers have changed."); 1520 } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 1521 MediaFormat oformat = codec.getOutputFormat(); 1522 audioParams.setNumChannels(oformat.getInteger(MediaFormat.KEY_CHANNEL_COUNT)); 1523 audioParams.setSamplingRate(oformat.getInteger(MediaFormat.KEY_SAMPLE_RATE)); 1524 Log.d(TAG, "output format has changed to " + oformat); 1525 } else { 1526 Log.d(TAG, "dequeueOutputBuffer returned " + res); 1527 } 1528 } 1529 1530 if (noOutputCounter >= 50) { 1531 fail("decoder stopped outputting data"); 1532 } 1533 1534 // check if MediaCodec gives back correct drc parameters 1535 if (drcParams != null && sIsAndroidRAndAbove) { 1536 if (drcParams.mAlbumMode != 0) { 1537 final int albumModeFromCodec = DecoderTest.getOutputFormatInteger(codec, 1538 MediaFormat.KEY_AAC_DRC_ALBUM_MODE); 1539 assertEquals("DRC AlbumMode received from MediaCodec is not the Album Mode set" 1540 + " runtime:" + runtimeChange, drcParams.mAlbumMode, albumModeFromCodec); 1541 } 1542 if (drcParams.mEffectType != 0) { 1543 final int effectTypeFromCodec = DecoderTest.getOutputFormatInteger(codec, 1544 MediaFormat.KEY_AAC_DRC_EFFECT_TYPE); 1545 assertEquals("DRC Effect Type received from MediaCodec is not the Effect Type set" 1546 + " runtime:" + runtimeChange, drcParams.mEffectType, effectTypeFromCodec); 1547 } 1548 if (drcParams.mDecoderTargetLevel != 0) { 1549 final int targetLevelFromCodec = DecoderTest.getOutputFormatInteger(codec, 1550 MediaFormat.KEY_AAC_DRC_TARGET_REFERENCE_LEVEL); 1551 assertEquals("DRC Target Ref Level received from MediaCodec is not the level set" 1552 + " runtime:" + runtimeChange, 1553 drcParams.mDecoderTargetLevel, targetLevelFromCodec); 1554 } 1555 1556 final int cutFromCodec = DecoderTest.getOutputFormatInteger(codec, 1557 MediaFormat.KEY_AAC_DRC_ATTENUATION_FACTOR); 1558 assertEquals("Attenuation factor received from MediaCodec differs from set:", 1559 drcParams.mCut, cutFromCodec); 1560 final int boostFromCodec = DecoderTest.getOutputFormatInteger(codec, 1561 MediaFormat.KEY_AAC_DRC_BOOST_FACTOR); 1562 assertEquals("Boost factor received from MediaCodec differs from set:", 1563 drcParams.mBoost, boostFromCodec); 1564 } 1565 1566 // expectedOutputLoudness == -2 indicates that output loudness is not tested 1567 if (expectedOutputLoudness != -2 && sIsAndroidRAndAbove) { 1568 final int outputLoudnessFromCodec = DecoderTest.getOutputFormatInteger(codec, 1569 MediaFormat.KEY_AAC_DRC_OUTPUT_LOUDNESS); 1570 if (outputLoudnessFromCodec != expectedOutputLoudness) { 1571 fail("Received decoder output loudness is not the expected value"); 1572 } 1573 } 1574 1575 codec.stop(); 1576 codec.release(); 1577 return decoded; 1578 } 1579 1580 private short[] decodeToMemory(AudioParameter audioParams, int testinput, 1581 int eossample, List<Long> timestamps, DrcParams drcParams, String decoderName) 1582 throws IOException 1583 { 1584 final short[] decoded = decodeToMemory(audioParams, testinput, eossample, timestamps, 1585 drcParams, decoderName, false, -2, false, 0, 0); 1586 return decoded; 1587 } 1588 1589 private short[] decodeToMemory(AudioParameter audioParams, int testinput, 1590 int eossample, List<Long> timestamps, DrcParams drcParams, String decoderName, 1591 boolean runtimeChange) 1592 throws IOException 1593 { 1594 final short[] decoded = decodeToMemory(audioParams, testinput, eossample, timestamps, 1595 drcParams, decoderName, runtimeChange, -2, false, 0, 0); 1596 return decoded; 1597 } 1598 1599 private short[] decodeToMemory(AudioParameter audioParams, int testinput, 1600 int eossample, List<Long> timestamps, DrcParams drcParams, String decoderName, 1601 boolean runtimeChange, int expectedOutputLoudness) 1602 throws IOException 1603 { 1604 short [] decoded = decodeToMemory(audioParams, testinput, eossample, timestamps, drcParams, 1605 decoderName, runtimeChange, expectedOutputLoudness, false, 0, 0); 1606 return decoded; 1607 } 1608 } 1609 1610