• 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.videocodec.cts;
18 
19 import static android.media.MediaFormat.PICTURE_TYPE_I;
20 import static android.media.MediaFormat.PICTURE_TYPE_UNKNOWN;
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.fail;
25 
26 import android.media.Image;
27 import android.media.MediaCodec;
28 import android.media.MediaFormat;
29 import android.mediav2.common.cts.BitStreamUtils;
30 import android.mediav2.common.cts.CodecEncoderTestBase;
31 import android.mediav2.common.cts.DecodeStreamToYuv;
32 import android.mediav2.common.cts.EncoderConfigParams;
33 import android.mediav2.common.cts.RawResource;
34 import android.util.Log;
35 
36 import androidx.annotation.NonNull;
37 
38 import com.android.compatibility.common.util.Preconditions;
39 
40 import java.io.File;
41 import java.io.IOException;
42 import java.io.RandomAccessFile;
43 import java.nio.ByteBuffer;
44 import java.util.ArrayList;
45 import java.util.HashMap;
46 import java.util.Objects;
47 import java.util.TreeMap;
48 
49 /**
50  * Wrapper class for handling and testing video encoder components.
51  */
52 public class VideoEncoderValidationTestBase extends CodecEncoderTestBase {
53     private static final String LOG_TAG = VideoEncoderValidationTestBase.class.getSimpleName();
54     private static final String MEDIA_DIR = WorkDir.getMediaDirString();
55 
56     protected static final boolean ENABLE_LOGS = false;
57     protected static final StringBuilder DIAGNOSTICS = new StringBuilder();
58 
59     protected final CompressedResource mCRes;
60     protected BitStreamUtils.ParserBase mParser;
61 
62     final TreeMap<Long, Integer> mPtsPicTypeMap = new TreeMap<>();
63 
64     RandomAccessFile mFileInp;
65     long mFileReadOffset;
66     long mFileLength;
67 
68     public static class CompressedResource {
69         final String mMediaType;
70         final String mResFile;
71 
CompressedResource(String mediaType, String resFile)72         CompressedResource(String mediaType, String resFile) {
73             mMediaType = mediaType;
74             mResFile = resFile;
75         }
76 
77         @NonNull
78         @Override
toString()79         public String toString() {
80             return "CompressedResource{" + "res file ='" + mResFile + '\'' + '}';
81         }
82 
uniqueLabel()83         public String uniqueLabel() {
84             return mMediaType + mResFile;
85         }
86     }
87 
88     public static final CompressedResource BIRTHDAY_FULLHD_LANDSCAPE =
89             new CompressedResource(MediaFormat.MIMETYPE_VIDEO_AVC, MEDIA_DIR
90                     + "AVICON-MOBILE-BirthdayHalfway-SI17-CRUW03-L-420-8bit-SDR-1080p-30fps.mp4");
91     public static final CompressedResource SELFIEGROUP_FULLHD_PORTRAIT =
92             new CompressedResource(MediaFormat.MIMETYPE_VIDEO_AVC, MEDIA_DIR
93                     + "AVICON-MOBILE-SelfieGroupGarden-SF15-CF01-P-420-8bit-SDR-1080p-30fps.mp4");
94 
logAllFilesInCacheDir(boolean isStartOfTest)95     static void logAllFilesInCacheDir(boolean isStartOfTest) {
96         if (isStartOfTest) DIAGNOSTICS.setLength(0);
97         String cacheDir = CONTEXT.getCacheDir().toString();
98         DIAGNOSTICS.append(String.format("\nThe state of cache dir : %s, %s is :", cacheDir,
99                 isStartOfTest ? "at start" : "now"));
100         File dir = new File(cacheDir);
101         if (dir.exists()) {
102             for (File f : Objects.requireNonNull(dir.listFiles())) {
103                 DIAGNOSTICS.append(f.getName()).append("\n");
104             }
105         } else {
106             DIAGNOSTICS.append(" directory not present");
107         }
108     }
109 
decodeStreamsToYuv(ArrayList<CompressedResource> resources, HashMap<String, RawResource> streamYuvMap, String prefix)110     static void decodeStreamsToYuv(ArrayList<CompressedResource> resources,
111             HashMap<String, RawResource> streamYuvMap, String prefix) {
112         decodeStreamsToYuv(resources, streamYuvMap, Integer.MAX_VALUE, prefix);
113     }
114 
decodeStreamsToYuv(ArrayList<CompressedResource> resources, HashMap<String, RawResource> streamYuvMap, int frameLimit, String prefix)115     static void decodeStreamsToYuv(ArrayList<CompressedResource> resources,
116             HashMap<String, RawResource> streamYuvMap, int frameLimit, String prefix) {
117         logAllFilesInCacheDir(true);
118         for (CompressedResource res : resources) {
119             if (!(streamYuvMap.containsKey(res.uniqueLabel()))) {
120                 try {
121                     DecodeStreamToYuv yuv = new DecodeStreamToYuv(res.mMediaType, res.mResFile,
122                             frameLimit, prefix);
123                     streamYuvMap.put(res.uniqueLabel(), yuv.getDecodedYuv());
124                 } catch (Exception e) {
125                     streamYuvMap.put(res.uniqueLabel(), null);
126                     DIAGNOSTICS.append(String.format("\nWhile decoding the resource : %s,"
127                             + " encountered exception :  %s was thrown", res, e));
128                     logAllFilesInCacheDir(false);
129                 }
130             }
131         }
132     }
133 
VideoEncoderValidationTestBase(String encoder, String mediaType, EncoderConfigParams encCfgParams, CompressedResource res, String allTestParams)134     VideoEncoderValidationTestBase(String encoder, String mediaType,
135             EncoderConfigParams encCfgParams, CompressedResource res, String allTestParams) {
136         super(encoder, mediaType, new EncoderConfigParams[]{encCfgParams}, allTestParams);
137         mCRes = res;
138     }
139 
setUpSource(String inpPath)140     protected void setUpSource(String inpPath) throws IOException {
141         Preconditions.assertTestFileExists(inpPath);
142         mFileInp = new RandomAccessFile(inpPath, "r");
143         mInputData = null;
144         mFileReadOffset = 0L;
145         mFileLength = mFileInp.length();
146     }
147 
resetContext(boolean isAsync, boolean signalEOSWithLastFrame)148     protected void resetContext(boolean isAsync, boolean signalEOSWithLastFrame) {
149         super.resetContext(isAsync, signalEOSWithLastFrame);
150         mPtsPicTypeMap.clear();
151     }
152 
enqueueInput(int bufferIndex)153     protected void enqueueInput(int bufferIndex) {
154         int frmSize = 3 * mActiveRawRes.mBytesPerSample * mActiveRawRes.mWidth
155                 * mActiveRawRes.mHeight / 2;
156         if (mInputData == null || mInputData.length != frmSize) {
157             mInputData = new byte[frmSize];
158         }
159         int bytesRead = 0;
160         try {
161             bytesRead = mFileInp.read(mInputData);
162             if (mIsLoopBack && mInputCount < mLoopBackFrameLimit && bytesRead == -1) {
163                 mFileInp.seek(0);
164                 bytesRead = mFileInp.read(mInputData);
165             }
166         } catch (IOException e) {
167             fail("encountered exception during file read." + e + "\n" + mTestConfig + mTestEnv);
168         }
169         if (bytesRead != -1 && bytesRead != frmSize) {
170             fail("received partial frame to encode \n" + mTestConfig + mTestEnv);
171         }
172         if (bytesRead == -1) {
173             assertEquals("mFileReadOffset, mFileLength and EOS state are not in sync \n"
174                     + mTestConfig + mTestEnv, mFileReadOffset, mFileLength);
175             enqueueEOS(bufferIndex);
176         } else {
177             int size = mActiveRawRes.mBytesPerSample * mActiveEncCfg.mWidth
178                     * mActiveEncCfg.mHeight * 3 / 2;
179             int flags = 0;
180             long pts = mInputOffsetPts + mInputCount * 1000000L / mActiveEncCfg.mFrameRate;
181 
182             Image img = mCodec.getInputImage(bufferIndex);
183             assertNotNull("CPU-read via ImageReader API is not available \n" + mTestConfig
184                     + mTestEnv, img);
185             fillImage(img);
186             if (mSignalEOSWithLastFrame) {
187                 if (mIsLoopBack ? (mInputCount + 1 >= mLoopBackFrameLimit) :
188                         (mFileReadOffset + frmSize >= mFileLength)) {
189                     flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
190                     mSawInputEOS = true;
191                 }
192             }
193             mNumBytesSubmitted += size;
194             mFileReadOffset += frmSize;
195             mCodec.queueInputBuffer(bufferIndex, 0, size, pts, flags);
196             if (ENABLE_LOGS) {
197                 Log.v(LOG_TAG, "input: id: " + bufferIndex + " size: " + size + " pts: " + pts
198                         + " flags: " + flags);
199             }
200             mOutputBuff.saveInPTS(pts);
201             mInputCount++;
202         }
203     }
204 
dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info)205     protected void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
206         if (info.size > 0 && ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0)) {
207             int picType = PICTURE_TYPE_UNKNOWN;
208 
209             if ((info.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) {
210                 picType = PICTURE_TYPE_I;
211             }
212             if (picType == PICTURE_TYPE_UNKNOWN) {
213                 MediaFormat format = mCodec.getOutputFormat(bufferIndex);
214                 picType = format.getInteger(MediaFormat.KEY_PICTURE_TYPE, PICTURE_TYPE_UNKNOWN);
215             }
216             if (picType == PICTURE_TYPE_UNKNOWN && mParser != null) {
217                 ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
218                 picType = BitStreamUtils.getFrameTypeFromBitStream(buf, info, mParser);
219             }
220             mPtsPicTypeMap.put(info.presentationTimeUs, picType);
221         }
222         super.dequeueOutput(bufferIndex, info);
223     }
224 }
225