• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.mediav2.common.cts;
18 
19 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
20 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
21 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
22 import static android.media.codec.Flags.subsessionMetrics;
23 
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28 import static org.junit.Assume.assumeTrue;
29 
30 import android.graphics.ImageFormat;
31 import android.media.Image;
32 import android.media.MediaCodec;
33 import android.media.MediaCodecInfo;
34 import android.media.MediaExtractor;
35 import android.media.MediaFormat;
36 import android.os.PersistableBundle;
37 import android.util.Log;
38 import android.util.Pair;
39 
40 import com.android.compatibility.common.util.Preconditions;
41 
42 import org.junit.After;
43 import org.junit.Before;
44 
45 import java.io.IOException;
46 import java.nio.ByteBuffer;
47 import java.util.ArrayList;
48 import java.util.Locale;
49 
50 /**
51  * Wrapper class for trying and testing mediacodec decoder components.
52  */
53 public class CodecDecoderTestBase extends CodecTestBase {
54     private static final String LOG_TAG = CodecDecoderTestBase.class.getSimpleName();
55 
56     protected final String mTestFile;
57     protected boolean mIsInterlaced;
58     protected boolean mSkipChecksumVerification;
59 
60     protected final ArrayList<ByteBuffer> mCsdBuffers;
61     protected int mCurrCsdIdx;
62 
63     protected final ByteBuffer mFlatBuffer = ByteBuffer.allocate(4 * Integer.BYTES);
64 
65     protected MediaExtractor mExtractor;
66 
CodecDecoderTestBase(String codecName, String mediaType, String testFile, String allTestParams)67     public CodecDecoderTestBase(String codecName, String mediaType, String testFile,
68             String allTestParams) {
69         super(codecName, mediaType, allTestParams);
70         mTestFile = testFile;
71         mCsdBuffers = new ArrayList<>();
72     }
73 
74     @Before
setUpCodecDecoderTestBase()75     public void setUpCodecDecoderTestBase() {
76         assertTrue("Testing a mediaType that is neither audio nor video is not supported \n"
77                 + mTestConfig, mIsAudio || mIsVideo);
78     }
79 
80     @After
tearDownCodecDecoderTestBase()81     public void tearDownCodecDecoderTestBase() {
82         if (mExtractor != null) {
83             mExtractor.release();
84             mExtractor = null;
85         }
86     }
87 
getMaxSampleSizeForMediaType(String fileName, String mediaType)88     public static int getMaxSampleSizeForMediaType(String fileName, String mediaType)
89             throws IOException {
90         Preconditions.assertTestFileExists(fileName);
91         int maxSampleSize = 0;
92         MediaExtractor extractor = new MediaExtractor();
93         extractor.setDataSource(fileName);
94         for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) {
95             MediaFormat format = extractor.getTrackFormat(trackID);
96             if (mediaType.equalsIgnoreCase(format.getString(MediaFormat.KEY_MIME))) {
97                 extractor.selectTrack(trackID);
98                 if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
99                     maxSampleSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
100                 } else {
101                     int size;
102                     while ((size = (int) extractor.getSampleSize()) != -1) {
103                         maxSampleSize = Math.max(maxSampleSize, size);
104                         extractor.advance();
105                     }
106                 }
107                 extractor.release();
108                 return maxSampleSize;
109             }
110         }
111         fail("No track with mediaType: " + mediaType + " found in file: " + fileName + "\n");
112         return maxSampleSize;
113     }
114 
setUpSource(String srcFile)115     protected MediaFormat setUpSource(String srcFile) throws IOException {
116         Preconditions.assertTestFileExists(srcFile);
117         mExtractor = new MediaExtractor();
118         mExtractor.setDataSource(srcFile);
119         for (int trackID = 0; trackID < mExtractor.getTrackCount(); trackID++) {
120             MediaFormat format = mExtractor.getTrackFormat(trackID);
121             if (mMediaType.equalsIgnoreCase(format.getString(MediaFormat.KEY_MIME))) {
122                 // This is required for some mlaw and alaw test vectors where access unit size is
123                 // exceeding default max input size
124                 if (mMediaType.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW)
125                         || mMediaType.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) {
126                     format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE,
127                             getMaxSampleSizeForMediaType(srcFile, mMediaType));
128                 }
129                 mExtractor.selectTrack(trackID);
130                 if (mIsVideo) {
131                     ArrayList<MediaFormat> formatList = new ArrayList<>();
132                     formatList.add(format);
133                     boolean selectHBD = doesAnyFormatHaveHDRProfile(mMediaType, formatList);
134                     if (!selectHBD && srcFile.contains("10bit")) {
135                         selectHBD = true;
136                     }
137                     format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
138                             getColorFormat(mCodecName, mMediaType, mSurface != null, selectHBD));
139                     if (selectHBD && (format.getInteger(MediaFormat.KEY_COLOR_FORMAT)
140                             != COLOR_FormatYUVP010)) {
141                         mSkipChecksumVerification = true;
142                     }
143 
144                     if ((format.getInteger(MediaFormat.KEY_COLOR_FORMAT) != COLOR_FormatYUVP010)
145                             && selectHBD && mSurface == null) {
146                         // Codecs that do not advertise P010 on devices with VNDK version < T, do
147                         // not support decoding high bit depth clips when color format is set to
148                         // COLOR_FormatYUV420Flexible in byte buffer mode. Since byte buffer mode
149                         // for high bit depth decoding wasn't tested prior to Android T, skip this
150                         // when device is older
151                         assumeTrue("Skipping High Bit Depth tests on VNDK < T", VNDK_IS_AT_LEAST_T);
152                     }
153                 }
154                 // TODO: determine this from the extractor format when it becomes exposed.
155                 mIsInterlaced = srcFile.contains("_interlaced_");
156                 return format;
157             }
158         }
159         fail("No track with mediaType: " + mMediaType + " found in file: " + srcFile + "\n"
160                 + mTestConfig + mTestEnv);
161         return null;
162     }
163 
doOutputFormatChecks(MediaFormat defaultFormat, MediaFormat configuredFormat)164     protected void doOutputFormatChecks(MediaFormat defaultFormat, MediaFormat configuredFormat) {
165         String msg = String.format("Input test file format is not same as default format of"
166                 + " component, but test did not receive INFO_OUTPUT_FORMAT_CHANGED signal"
167                 + ".\nInput file format is :- %s \nDefault format is :- %s \n",
168                 configuredFormat, defaultFormat);
169         assertTrue(msg + mTestConfig + mTestEnv,
170                 mIsCodecInAsyncMode ? mAsyncHandle.hasOutputFormatChanged() :
171                 mSignalledOutFormatChanged);
172 
173         MediaFormat outputFormat =
174                 mIsCodecInAsyncMode ? mAsyncHandle.getOutputFormat() : mOutFormat;
175         msg = String.format("Configured input format and received output format are "
176             + "not similar. \nConfigured Input format is :- %s \nReceived Output "
177             + "format is :- %s \n", configuredFormat, outputFormat);
178         assertTrue(msg + mTestConfig + mTestEnv, isFormatSimilar(configuredFormat, outputFormat));
179     }
180 
getColorFormat(String name, String mediaType, boolean surfaceMode, boolean hbdMode)181     int getColorFormat(String name, String mediaType, boolean surfaceMode, boolean hbdMode) {
182         if (surfaceMode) return COLOR_FormatSurface;
183         if (hbdMode) {
184             MediaCodecInfo.CodecCapabilities cap = null;
185             for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) {
186                 if (name.equals(codecInfo.getName())) {
187                     cap = codecInfo.getCapabilitiesForType(mediaType);
188                     break;
189                 }
190             }
191             assertNotNull("did not receive capabilities for codec: " + name + ", media type: "
192                     + mediaType + "\n" + mTestConfig + mTestEnv, cap);
193             for (int c : cap.colorFormats) {
194                 if (c == COLOR_FormatYUVP010) {
195                     return c;
196                 }
197             }
198         }
199         return COLOR_FormatYUV420Flexible;
200     }
201 
hasCSD(MediaFormat format)202     public static boolean hasCSD(MediaFormat format) {
203         return format.containsKey("csd-0");
204     }
205 
flattenBufferInfo(MediaCodec.BufferInfo info, boolean isAudio)206     protected void flattenBufferInfo(MediaCodec.BufferInfo info, boolean isAudio) {
207         if (isAudio) {
208             mFlatBuffer.putInt(info.size);
209         }
210         mFlatBuffer.putInt(info.flags & ~MediaCodec.BUFFER_FLAG_END_OF_STREAM)
211                 .putLong(info.presentationTimeUs);
212         mFlatBuffer.flip();
213     }
214 
enqueueCodecConfig(int bufferIndex)215     void enqueueCodecConfig(int bufferIndex) {
216         ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
217         ByteBuffer csdBuffer = mCsdBuffers.get(mCurrCsdIdx);
218         inputBuffer.put((ByteBuffer) csdBuffer.rewind());
219         mCodec.queueInputBuffer(bufferIndex, 0, csdBuffer.limit(), 0,
220                 MediaCodec.BUFFER_FLAG_CODEC_CONFIG);
221         if (ENABLE_LOGS) {
222             Log.v(LOG_TAG, "queued csd: id: " + bufferIndex + " size: " + csdBuffer.limit());
223         }
224     }
225 
enqueueInput(int bufferIndex)226     protected void enqueueInput(int bufferIndex) {
227         if (mExtractor.getSampleSize() < 0) {
228             enqueueEOS(bufferIndex);
229         } else {
230             ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
231             mExtractor.readSampleData(inputBuffer, 0);
232             int size = (int) mExtractor.getSampleSize();
233             long pts = mExtractor.getSampleTime();
234             int extractorFlags = mExtractor.getSampleFlags();
235             int codecFlags = 0;
236             if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
237                 codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
238             }
239             if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_PARTIAL_FRAME) != 0) {
240                 codecFlags |= MediaCodec.BUFFER_FLAG_PARTIAL_FRAME;
241             }
242             if (!mExtractor.advance() && mSignalEOSWithLastFrame) {
243                 codecFlags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
244                 mSawInputEOS = true;
245             }
246             if (ENABLE_LOGS) {
247                 Log.v(LOG_TAG, "input: id: " + bufferIndex + " size: " + size + " pts: " + pts
248                         + " flags: " + codecFlags);
249             }
250             mCodec.queueInputBuffer(bufferIndex, 0, size, pts, codecFlags);
251             if (size > 0 && (codecFlags & (MediaCodec.BUFFER_FLAG_CODEC_CONFIG
252                     | MediaCodec.BUFFER_FLAG_PARTIAL_FRAME)) == 0) {
253                 mOutputBuff.saveInPTS(pts);
254                 mInputCount++;
255             }
256         }
257     }
258 
enqueueInput(int bufferIndex, ByteBuffer buffer, MediaCodec.BufferInfo info)259     protected void enqueueInput(int bufferIndex, ByteBuffer buffer, MediaCodec.BufferInfo info) {
260         ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
261         buffer.position(info.offset);
262         for (int i = 0; i < info.size; i++) {
263             inputBuffer.put(buffer.get());
264         }
265         if (ENABLE_LOGS) {
266             Log.v(LOG_TAG, "input: id: " + bufferIndex + " flags: " + info.flags + " size: "
267                     + info.size + " timestamp: " + info.presentationTimeUs);
268         }
269         mCodec.queueInputBuffer(bufferIndex, 0, info.size, info.presentationTimeUs,
270                 info.flags);
271         if (info.size > 0 && ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0)
272                 && ((info.flags & MediaCodec.BUFFER_FLAG_PARTIAL_FRAME) == 0)) {
273             mOutputBuff.saveInPTS(info.presentationTimeUs);
274             mInputCount++;
275         }
276         if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
277             mSawInputEOS = true;
278         }
279     }
280 
dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info)281     protected void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
282         if (info.size > 0 && mSaveToMem) {
283             ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
284             flattenBufferInfo(info, mIsAudio);
285             mOutputBuff.checksum(mFlatBuffer, mFlatBuffer.limit());
286             if (mIsAudio) {
287                 mOutputBuff.checksum(buf, info);
288                 mOutputBuff.saveToMemory(buf, info);
289             } else {
290                 // tests both getOutputImage and getOutputBuffer. Can do time division
291                 // multiplexing but lets allow it for now
292                 Image img = mCodec.getOutputImage(bufferIndex);
293                 assertNotNull("CPU-read via ImageReader API is not available", img);
294                 mOutputBuff.checksum(img);
295                 int imgFormat = img.getFormat();
296                 int bytesPerSample = (ImageFormat.getBitsPerPixel(imgFormat) * 2) / (8 * 3);
297 
298                 MediaFormat format = mCodec.getOutputFormat();
299                 buf = mCodec.getOutputBuffer(bufferIndex);
300                 int width = format.getInteger(MediaFormat.KEY_WIDTH);
301                 int height = format.getInteger(MediaFormat.KEY_HEIGHT);
302                 int stride = format.getInteger(MediaFormat.KEY_STRIDE);
303                 mOutputBuff.checksum(buf, info.size, width, height, stride, bytesPerSample);
304             }
305         }
306         if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
307             mSawOutputEOS = true;
308         }
309         if (ENABLE_LOGS) {
310             Log.v(LOG_TAG, "output: id: " + bufferIndex + " flags: " + info.flags + " size: "
311                     + info.size + " timestamp: " + info.presentationTimeUs);
312         }
313         if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
314             mOutputBuff.saveOutPTS(info.presentationTimeUs);
315             mOutputCount++;
316         }
317         mCodec.releaseOutputBuffer(bufferIndex, false);
318     }
319 
doWork(ByteBuffer buffer, ArrayList<MediaCodec.BufferInfo> list)320     protected void doWork(ByteBuffer buffer, ArrayList<MediaCodec.BufferInfo> list)
321             throws InterruptedException {
322         int frameCount = 0;
323         if (mIsCodecInAsyncMode) {
324             // output processing after queuing EOS is done in waitForAllOutputs()
325             while (!mAsyncHandle.hasSeenError() && !mSawInputEOS && frameCount < list.size()) {
326                 Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
327                 if (element != null) {
328                     int bufferID = element.first;
329                     MediaCodec.BufferInfo info = element.second;
330                     if (info != null) {
331                         dequeueOutput(bufferID, info);
332                     } else {
333                         enqueueInput(bufferID, buffer, list.get(frameCount));
334                         frameCount++;
335                     }
336                 }
337             }
338         } else {
339             MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
340             // output processing after queuing EOS is done in waitForAllOutputs()
341             while (!mSawInputEOS && frameCount < list.size()) {
342                 int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
343                 if (outputBufferId >= 0) {
344                     dequeueOutput(outputBufferId, outInfo);
345                 } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
346                     mOutFormat = mCodec.getOutputFormat();
347                     mSignalledOutFormatChanged = true;
348                 }
349                 int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
350                 if (inputBufferId != -1) {
351                     enqueueInput(inputBufferId, buffer, list.get(frameCount));
352                     frameCount++;
353                 }
354             }
355         }
356     }
357 
queueCodecConfig()358     protected void queueCodecConfig() throws InterruptedException {
359         if (mIsCodecInAsyncMode) {
360             for (mCurrCsdIdx = 0; !mAsyncHandle.hasSeenError() && mCurrCsdIdx < mCsdBuffers.size();
361                     mCurrCsdIdx++) {
362                 Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getInput();
363                 if (element != null) {
364                     enqueueCodecConfig(element.first);
365                 }
366             }
367         } else {
368             for (mCurrCsdIdx = 0; mCurrCsdIdx < mCsdBuffers.size(); mCurrCsdIdx++) {
369                 enqueueCodecConfig(mCodec.dequeueInputBuffer(-1));
370             }
371         }
372     }
373 
374     @Override
validateTestState()375     protected void validateTestState() {
376         super.validateTestState();
377         if (!mOutputBuff.isPtsStrictlyIncreasing(mPrevOutputPts)) {
378             fail("Output timestamps are not strictly increasing \n" + mTestConfig + mTestEnv
379                     + mOutputBuff.getErrMsg());
380         }
381         if (mIsVideo) {
382             // TODO: Timestamps for deinterlaced content are under review. (E.g. can decoders
383             // produce multiple progressive frames?) For now, do not verify timestamps.
384             if (!mIsInterlaced && !mOutputBuff.isOutPtsListIdenticalToInpPtsList(false)) {
385                 fail("Input pts list and Output pts list are not identical ]\n" + mTestConfig
386                         + mTestEnv + mOutputBuff.getErrMsg());
387             }
388             if (IS_AT_LEAST_B && subsessionMetrics()) {
389                 int min = mAsyncHandle.getMinExpectedMetricsFlushCount();
390                 int got = mAsyncHandle.getActualMetricsFlushCount();
391                 if (min > got) {
392                     fail(String.format(Locale.getDefault(),
393                             "min expected metrics flush count is %d, but got %d \n" + mTestConfig
394                                     + mTestEnv, min, got));
395                 }
396             }
397         }
398     }
399 
400     /**
401      * This function decodes the input file using the component given and stores the result in
402      * OutputManager. By default the decoded frames pts information is stored. This is used for
403      * general validation. Storing decoded frames is dependent on saveToMem argument and
404      * mediaType.
405      * <ul>
406      *     <li>If saveToMem is true and mediaType is audio, then the raw output is stored in a
407      *     byte buffer.</li>
408      *     <li>If saveToMem is true and mediaType is video, it is unrealistic to store all the
409      *     frames in raw format as it occupies huge space. So, for them their checksum is
410      *     preserved.</li>
411      * </ul>
412      */
decodeToMemory(String file, String decoder, OutputManager outputBuff, boolean saveToMem, long pts, int mode, int frameLimit, boolean isAsync, boolean signalledEos)413     public void decodeToMemory(String file, String decoder, OutputManager outputBuff,
414             boolean saveToMem, long pts, int mode, int frameLimit, boolean isAsync,
415             boolean signalledEos) throws IOException, InterruptedException {
416         mSaveToMem = saveToMem;
417         mOutputBuff = outputBuff;
418         mCodec = MediaCodec.createByCodecName(decoder);
419         MediaFormat format = setUpSource(file);
420         configureCodec(format, isAsync, signalledEos, false);
421         mCodec.start();
422         mExtractor.seekTo(pts, mode);
423         doWork(frameLimit);
424         queueEOS();
425         waitForAllOutputs();
426         mCodec.stop();
427         mCodec.release();
428         mExtractor.release();
429         mSaveToMem = false;
430     }
431 
decodeToMemory(String file, String decoder, OutputManager outputBuff, long pts, int mode, int frameLimit, boolean isAsync, boolean signalledEos)432     public void decodeToMemory(String file, String decoder, OutputManager outputBuff, long pts,
433             int mode, int frameLimit, boolean isAsync, boolean signalledEos)
434             throws IOException, InterruptedException {
435         decodeToMemory(file, decoder, outputBuff, true, pts, mode, frameLimit, isAsync,
436                 signalledEos);
437     }
438 
decodeToMemory(String file, String decoder, OutputManager outputBuff, long pts, int mode, int frameLimit)439     public void decodeToMemory(String file, String decoder, OutputManager outputBuff, long pts,
440             int mode, int frameLimit) throws IOException, InterruptedException {
441         decodeToMemory(file, decoder, outputBuff, pts, mode, frameLimit, false, true);
442     }
443 
decodeToMemory(String file, String decoder, long pts, int mode, int frameLimit)444     public void decodeToMemory(String file, String decoder, long pts, int mode, int frameLimit)
445             throws IOException, InterruptedException {
446         decodeToMemory(file, decoder, new OutputManager(), pts, mode, frameLimit);
447     }
448 
decodeToMemory(ByteBuffer buffer, ArrayList<MediaCodec.BufferInfo> list, MediaFormat format, String decoder)449     public void decodeToMemory(ByteBuffer buffer, ArrayList<MediaCodec.BufferInfo> list,
450             MediaFormat format, String decoder) throws IOException, InterruptedException {
451         mSaveToMem = true;
452         mOutputBuff = new OutputManager();
453         mCodec = MediaCodec.createByCodecName(decoder);
454         configureCodec(format, false, true, false);
455         mCodec.start();
456         doWork(buffer, list);
457         queueEOS();
458         waitForAllOutputs();
459         mCodec.stop();
460         mCodec.release();
461         mSaveToMem = false;
462     }
463 
464     @Override
validateMetrics(String decoder, MediaFormat format)465     protected PersistableBundle validateMetrics(String decoder, MediaFormat format) {
466         PersistableBundle metrics = super.validateMetrics(decoder, format);
467         assertEquals("error! metrics#MetricsConstants.MIME_TYPE is not as expected \n" + mTestConfig
468                 + mTestEnv, metrics.getString(MediaCodec.MetricsConstants.MIME_TYPE), mMediaType);
469         assertEquals("error! metrics#MetricsConstants.ENCODER is not as expected \n" + mTestConfig
470                 + mTestEnv, 0, metrics.getInt(MediaCodec.MetricsConstants.ENCODER));
471         return metrics;
472     }
473 
validateColorAspects(int range, int standard, int transfer, boolean ignoreColorBox)474     public void validateColorAspects(int range, int standard, int transfer, boolean ignoreColorBox)
475             throws IOException, InterruptedException {
476         Preconditions.assertTestFileExists(mTestFile);
477         mOutputBuff = new OutputManager();
478         MediaFormat format = setUpSource(mTestFile);
479         if (ignoreColorBox) {
480             format.removeKey(MediaFormat.KEY_COLOR_RANGE);
481             format.removeKey(MediaFormat.KEY_COLOR_STANDARD);
482             format.removeKey(MediaFormat.KEY_COLOR_TRANSFER);
483         }
484         mCodec = MediaCodec.createByCodecName(mCodecName);
485         configureCodec(format, true, true, false);
486         mCodec.start();
487         doWork(1);
488         queueEOS();
489         waitForAllOutputs();
490         validateColorAspects(mCodec.getOutputFormat(), range, standard, transfer);
491         mCodec.stop();
492         mCodec.release();
493         mExtractor.release();
494     }
495 }
496